Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.OOoLayout.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 /**
7  * Layout Class for OOo files
8  *
9  * @author Anakeen
10  * @version $Id: Class.OOoLayout.php,v 1.16 2008/10/31 17:01:18 eric Exp $
11  * @package FDL
12  * @subpackage CORE
13  */
14 /**
15  */
16 
17 include_once ('Class.Layout.php');
18 include_once ('Lib.FileMime.php');
19 /**
20  * @class OOoLayout
21  * use an open document text file as template
22  */
23 class OOoLayout extends Layout
24 {
25  //############################################
26  //#
27  private $strip = 'Y';
28  public $encoding = "utf-8";
29 
30  private $saved_sections = array();
31  private $added_images = array();
32  private $removed_images = array();
33  //########################################################################
34  //# Public methods
35  //#
36  //#
37  public $content_template = '';
38  public $style_template = '';
39  public $meta_template = '';
40  public $template = '';
41  public $manifest = '';
42 
43  protected $arrayKeys = array();
44  protected $arrayMainKeys = array();
45  protected $rkeyxml = array();
46  protected $cibledir;
47  /**
48  * @var array error list
49  */
50  protected $errors = array();
51  /**
52  /**
53  * @var DOMDocument
54  */
55  protected $dom;
56  /**
57  * construct template using an open document text file
58  * @param string $caneva open document file of the template
59  * @param Action $action current action
60  * @param Doc $doc document
61  */
62  public function __construct($caneva = "", Action & $action = null, Doc & $doc = null)
63  {
64  $this->LOG = new Log("", "Layout");
65  $this->doc = $doc;
66  $this->template = "";
67  $this->action = & $action;
68  $this->generation = "";
69  $file = $caneva;
70  $this->file = "";
71  if ($caneva != "") {
72  if ((!file_exists($file)) && ($file[0] != '/')) {
73  $file = DEFAULT_PUBDIR . "/$file"; // try absolute
74 
75  }
76  if (file_exists($file)) {
77  if (filesize($file) > 0) {
78  $this->odf2content($file);
79  $this->file = $file;
80  }
81  } else {
82 
83  $this->template = "file [$caneva] not exists";
84  }
85  }
86  }
87  /**
88  * return inside string of a node
89  * @param DOMnode $node
90  * @return string
91  */
92  protected function innerXML(DOMnode & $node)
93  {
94  if (!$node) return false;
95  $document = $node->ownerDocument;
96  $nodeAsString = $document->saveXML($node);
97  preg_match('!<.*?>(.*)</.*?>!s', $nodeAsString, $match);
98  return $match[1];
99  }
100  /**
101  * @deprecated BLOCK are not supported
102  * Enter description here ...
103  * @param string $block
104  * @param string $aid
105  * @param string $vkey
106  * @return string
107  */
108  protected function parseListInBlock($block, $aid, $vkey)
109  {
110  deprecatedFunction();
111  $head = '<?xml version="1.0" encoding="UTF-8"?>
112 <office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0">';
113  $foot = '</office:document-content>';
114  $domblock = new DOMDocument();
115  $frag1 = '';
116  $frag2 = '';
117  $block = trim($block);
118  if (substr($block, 0, 2) == '</') {
119  // fragment of block
120  $firsttag = strpos($block, '>');
121  $lasttag = strrpos($block, '<');
122  $frag1 = substr($block, 0, $firsttag + 1);
123  $frag2 = substr($block, $lasttag);
124  $block = substr($block, $firsttag + 1, $lasttag - strlen($block));
125  // print("\nfrag1:$frag1 $lasttag rag2:$frag2\n");
126  // print("\n====================\n");
127  //print("\nNB:[$block]\n");
128 
129  }
130 
131  if (!$domblock->loadXML($head . $block . $foot)) {
132  print "\n=============\n";
133  print $head . trim($block) . $foot;
134  return $block;
135  }
136 
137  $lists = $domblock->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "list");
138  foreach ($lists as $list) {
139  /**
140  * @var $list DOMElement
141  */
142  $items = $list->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "list-item");
143  if ($items->length > 0) {
144  $item = $items->item(0);
145 
146  if (preg_match('/\[V_[A-Z0-9_-]+\]/', $item->textContent, $reg)) {
147  $skey = $reg[0];
148  // print "serack key : [$skey] [$aid] [$vkey]";
149  if ($skey == $aid) {
150  // $vkey=$this->rkey[$key];
151  $tvkey = explode('<text:tab/>', $vkey);
152 
153  foreach ($tvkey as $key) {
154  $clone = $item->cloneNode(true);
155  $item->parentNode->appendChild($clone);
156  $this->replaceNodeText($clone, $reg[0], $key);
157  }
158  $item->parentNode->removeChild($item);
159  }
160  }
161  }
162  }
163  return $frag1 . $this->innerXML($domblock->firstChild) . $frag2;
164  //return $frag1 . $domblock->saveXML($domblock->firstChild->firstChild) . $frag2;
165 
166  }
167 
168  protected function getAncestor(&$node, $type)
169  {
170  $mynode = $node;
171  while (!empty($mynode->parentNode)) {
172  $mynode = $mynode->parentNode;
173  if ($mynode->tagName == $type) {
174  return $mynode;
175  }
176  }
177  return false;
178  }
179  /**
180  * get depth in dom tree
181  * @param DOMNode $node
182  * @return int
183  */
184  private function getNodeDepth(DOMNode & $node)
185  {
186  $mynode = $node;
187  $depth = 0;
188  while (!empty($mynode->parentNode)) {
189  $depth++;
190  $mynode = $mynode->parentNode;
191  }
192  return $depth;
193  }
194 
195  protected function ParseBlock(&$out = null)
196  {
197  $this->template = preg_replace_callback('/(?m)\[BLOCK\s*([^\]]*)\](.*?)\[ENDBLOCK\s*\\1\]/s', function ($matches)
198  {
199  /** @noinspection PhpDeprecationInspection */
200  return $this->SetBlock($matches[1], $matches[2]);
201  }
202  , $this->template);
203  }
204  /**
205  *
206  * @param string $name name of the IF
207  * @param string $block xml string which containt the condition
208  * @param boolean $not negative condition
209  * @param array $levelPath Path use to retrieve condition value in recursive repeatable mode
210  * @return string
211  */
212  protected function TestIf($name, $block, $not = false, $levelPath = null)
213  {
214  $out = "";
215  $cond = null;
216  if ($levelPath) {
217  $val = $this->getArrayKeyValue($name, $levelPath);
218  if (is_array($val)) $val = null; // it is not the good level
219  if ($val !== null) $cond = ($val == true);
220  } else {
221  if (isset($this->rif[$name]) && $this->rif[$name] !== null) $cond = ($this->rif[$name] == true);
222  elseif (isset($this->rkey[$name]) && $this->rkey[$name] !== null) $cond = ($this->rkey[$name] == true);
223  }
224  if ($cond !== null) {
225  if ($cond xor $not) {
226  $out = $block;
227  }
228  } else {
229  // return condition
230  if ($not) $out = "[IFNOT $name]" . $block . "[ENDIF $name]";
231  else $out = "[IF $name]" . $block . "[ENDIF $name]";
232  }
233  if ($this->strip == 'Y') $out = str_replace("\\\"", "\"", $out);
234  return ($out);
235  }
236  /**
237  * Top level parse condition
238  * @param string|null $out
239  * @throws \Dcp\Exception
240  */
241  protected function ParseIf(&$out = null)
242  {
243  $templateori = '';
244  $level = 0;
245  //header('Content-type: text/xml; charset=utf-8');print $this->template;exit;
246  while ($templateori != $this->template && ($level < 10)) {
247  $templateori = $this->template;
248  $this->template = preg_replace_callback('/(?m)\[IF(NOT)?\s*([^\]]*)\](.*?)\[ENDIF\s*\\2\]/s', function ($matches)
249  {
250  return $this->TestIf($matches[2], $matches[3], $matches[1]);
251  }
252  , $this->template);
253  $level++; // to prevent infinite loop
254 
255  }
256  $this->fixSpanIf($this->template);
257  // header('Content-type: text/xml; charset=utf-8');print $this->template;exit;
258  // restore user fields
259  if (!$this->dom->loadXML($this->template)) {
260  print $this->template;
261  throw new Dcp\Exception("Error in parse condition");
262  }
263  //header('Content-type: text/xml; charset=utf-8');print $this->dom->saveXML();exit;
264  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "user-field-get");
265 
266  $domElemsToRemove = array();
267  $domElemsToClean = array();
268  foreach ($lists as $list) {
269  /**
270  * @var $list DOMElement
271  */
272  if (!$list->getAttribute('office:string-value')) {
273  if ($list->textContent == '') {
274  $domElemsToRemove[] = $list;
275  } else {
276  //$list->setAttribute("text:name",'');
277  $domElemsToClean[] = $list;
278  }
279  }
280  }
281  /**
282  * @var $domElemsToRemove DOMElement[]
283  */
284  foreach ($domElemsToRemove as $domElement) {
285  $domElement->parentNode->removeChild($domElement);
286  }
287 
288  $this->template = $this->dom->saveXML();
289  }
290  /**
291  * to not parse user fields set
292  */
293  protected function hideUserFieldSet()
294  {
295  //$this->dom->loadXML($this->template);
296  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "user-field-decl");
297  foreach ($lists as $list) {
298  /**
299  * @var $list DOMElement
300  */
301  $list->setAttribute('office:string-value', str_replace('[', '-CROCHET-', $list->getAttribute('office:string-value')));
302  $list->setAttribute('text:name', str_replace('[', '-CROCHET-', $list->getAttribute('text:name')));
303  }
304  // detect user field to force it into a span
305  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "user-field-get");
306  /**
307  * @var $list DOMElement
308  */
309  foreach ($lists as $list) {
310  /*
311  * @var DOMElement $lp
312  */
313  $lp = $list->parentNode;
314  if ($lp->tagName != 'text:span') {
315  $nt = $this->dom->createElement("text:span");
316  $lp->insertBefore($nt, $list);
317  $nt->appendChild($list);
318  }
319  }
320  // header('Content-type: text/xml; charset=utf-8');print $this->dom->saveXML();exit;
321  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "user-field-get");
322  $userFields = array();
323  // set the key of fields to up
324  foreach ($lists as $list) {
325  $textContent = $list->nodeValue;
326  if (substr($textContent, 0, 1) == '[') {
327  $userFields[] = $list;
328  $nt = $this->dom->createTextNode($textContent);
329  $list->parentNode->insertBefore($nt, $list);
330  }
331  }
332  foreach ($userFields as $list) {
333  $list->parentNode->removeChild($list);
334  }
335 
336  $this->template = $this->dom->saveXML();
337  }
338  /**
339  * to get xml warning as Exception
340  * @param string $strXml
341  * @return \Dcp\Utils\XDOMDocument
342  * @throws \Dcp\Utils\XDOMDocumentException
343  */
344  protected function XmlLoader($strXml)
345  {
346  $this->dom = new \Dcp\Utils\XDOMDocument();
347  $this->dom->loadXML($strXml);
348  return $this->dom;
349  }
350  /**
351  * replace brackets
352  */
353  protected function restoreUserFieldSet()
354  {
355  try {
356  $this->XmlLoader(\Dcp\Utils\htmlclean::cleanXMLUTF8($this->template));
357  }
358  catch(\Dcp\Utils\XDOMDocumentException $e) {
359  $outfile = uniqid(getTmpDir() . "/oooKo") . '.xml';
360  $this->addError("LAY0004", $outfile);
361  file_put_contents($outfile, $this->template);
362  $this->exitError($outfile);
363  }
364  /* if (!$this->dom->loadXML($this->template)) {
365 
366  $xmlErr=libxml_get_last_error();
367  if (is_array($xmlErr)) $err=sprintf("XML error line %d, column %d,: %s",$xmlErr["line"],$xmlErr["column"], $xmlErr["message"]);
368  else $err="";
369 
370  $outfile = uniqid(getTmpDir() . "/oooKo") . '.xml';
371  $this->addError("LAY0004", $outfile);
372  file_put_contents($outfile, $this->template);
373  $this->exitError($outfile);
374  }*/
375 
376  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "user-field-decl");
377 
378  foreach ($lists as $list) {
379  /**
380  * @var $list DOMElement
381  */
382  $list->setAttribute('office:string-value', str_replace('-CROCHET-', '[', $list->getAttribute('office:string-value')));
383  $list->setAttribute('text:name', str_replace('-CROCHET-', '[', $list->getAttribute('text:name')));
384  }
385  $this->template = $this->dom->saveXML();
386  }
387  /**
388  * not use for the moment
389  * @deprecated BLOCK are not supported
390  * @param $name
391  * @param $block
392  * @return string
393  */
394  protected function SetBlock($name, $block)
395  {
396  deprecatedFunction();
397  if ($this->strip == 'Y') {
398  // $block = StripSlashes($block);
399  $block = str_replace("\\\"", "\"", $block);
400  }
401  $out = "";
402  if (isset($this->data) && isset($this->data["$name"]) && is_array($this->data["$name"])) {
403  foreach ($this->data["$name"] as $k => $v) {
404  $loc = $block;
405 
406  foreach ($this->corresp["$name"] as $k2 => $v2) {
407 
408  if (strstr($v[$v2], '<text:tab/>')) {
409  /** @noinspection PhpDeprecationInspection */
410  $loc = $this->parseListInBlock($loc, $k2, $v[$v2]);
411  } elseif ((!is_object($v[$v2])) && (!is_array($v[$v2]))) $loc = str_replace($k2, $v[$v2], $loc);
412  }
413  $this->rif = & $v;
414  // $this->ParseIf($loc);
415  $out.= $loc;
416  }
417  }
418  // $this->ParseBlock($out);
419  return ($out);
420  }
421  /**
422  * not use for the moment
423  * @deprecated ZONE are not supported
424  * @param $out
425  */
426  protected function ParseZone(&$out)
427  {
428  deprecatedFunction();
429 
430  $out = preg_replace_callback('/\[ZONE\s*([^:]*):([^\]]*)\]/', function ($matches)
431  {
432  return $this->execute($matches[1], $matches[2]);
433  }
434  , $out);
435  }
436  /**
437  * replace simple key in xml string
438  * @param string|null $out
439  */
440  protected function ParseKey(&$out = null)
441  {
442  if (isset($this->rkey)) {
443  $this->template = str_replace($this->pkey, $this->rkey, $this->template);
444  }
445  }
446  /**
447  * read odt file and insert xmls in object
448  * @param string $odtfile path to the odt file
449  * @return string
450  * @throws \Dcp\Layout\Exception|\Dcp\Core\Exception
451  */
452  protected function odf2content($odtfile)
453  {
454  if (!file_exists($odtfile)) {
455  $this->addError("LAY0001", $odtfile);
456  $this->exitError();
457  }
458  $this->cibledir = uniqid(getTmpDir() . "/odf");
459 
460  $cmd = sprintf("unzip %s -d %s 2>&1", escapeshellarg($odtfile) , escapeshellarg($this->cibledir));
461  if (exec($cmd, $out, $ret) === false) {
462  $err = error_get_last();
463  if (isset($err['message'])) {
464  $err = $err['message'];
465  } else {
466  $err = 'unknown PHP error...';
467  }
468  throw new Dcp\Core\Exception("LAY0006", $err);
469  }
470  if ($ret !== 0) {
471  $err = join("\n", $out);
472  throw new Dcp\Core\Exception("LAY0007", $odtfile, $err);
473  }
474 
475  $contentxml = $this->cibledir . "/content.xml";
476  if (file_exists($contentxml)) {
477  $this->content_template = file_get_contents($contentxml);
478  unlink($contentxml);
479  }
480  $contentxml = $this->cibledir . "/META-INF/manifest.xml";
481  if (file_exists($contentxml)) {
482  $this->manifest = file_get_contents($contentxml);
483  unlink($contentxml);
484  }
485  $contentxml = $this->cibledir . "/styles.xml";
486  if (file_exists($contentxml)) {
487  $this->style_template = file_get_contents($contentxml);
488  unlink($contentxml);
489  }
490  $contentxml = $this->cibledir . "/meta.xml";
491  if (file_exists($contentxml)) {
492  $this->meta_template = file_get_contents($contentxml);
493  unlink($contentxml);
494  }
495  return '';
496  }
497  /**
498  * recompose odt file
499  * @param string $odsfile output file path
500  * @return string
501  */
502  protected function content2odf($odsfile)
503  {
504  if (file_exists($odsfile)) return "file $odsfile must not be present";
505 
506  $contentxml = $this->cibledir . "/content.xml";
507 
508  $this->content_template = preg_replace("!</?text:bookmark-(start|end)([^>]*)>!s", "", $this->content_template);
509  //$this->content_template=preg_replace("!<text:section>(\s*<text:p/>)+!s","<text:section>",$this->content_template);
510  //$this->content_template=preg_replace("!(<text:p/>\s*)+</text:section>!s","</text:section>",$this->content_template);
511  //$this->content_template=preg_replace("/<text:span([^>]*)>\s*<text:section>/s","<text:section>",$this->content_template);
512  //$this->content_template=preg_replace("/<\/text:section>\s*<\/text:span>/s","</text:section>",$this->content_template);
513  //$this->content_template=preg_replace("/<text:p([^>]*)>\s*<text:section([^>]*)>/s","<text:section\\2>",$this->content_template);
514  //$this->content_template=preg_replace("/<\/text:section>\s*<\/text:p>/s","</text:section>",$this->content_template);
515  //$this->content_template=preg_replace("/<text:p ([^>]*)>\s*<text:([^\/]*)\/>\s*<text:section[^>]*>/s","<text:section><text:\\2/>",$this->content_template);
516  //$this->content_template=preg_replace("/<\/text:section>\s*<text:([^\/]*)\/>\s*<\/text:p>/s","</text:section><text:\\1/>",$this->content_template);
517  //$this->content_template=preg_replace("/<table:table-cell ([^>]*)>\s*<text:section>/s","<table:table-cell \\1>",$this->content_template);
518  //$this->content_template=preg_replace("/<\/text:section>\s*<\/table:table-cell>/s","</table:table-cell>",$this->content_template);
519  $this->content_template = str_replace("&lt;text:line-break/&gt;", "<text:line-break/>", $this->content_template);
520  // header('Content-type: text/xml; charset=utf-8');print($this->content_template);exit;
521  file_put_contents($contentxml, $this->content_template);
522 
523  $contentxml = $this->cibledir . "/META-INF/manifest.xml";
524  file_put_contents($contentxml, $this->manifest);
525 
526  $contentxml = $this->cibledir . "/styles.xml";
527  file_put_contents($contentxml, $this->style_template);
528 
529  $contentxml = $this->cibledir . "/meta.xml";
530  file_put_contents($contentxml, $this->meta_template);
531 
532  $cmd = sprintf("cd %s;zip -q -Z store -X %s mimetype ;zip -q -r -X -u %s * && /bin/rm -fr %s", escapeshellarg($this->cibledir) , escapeshellarg($odsfile) , escapeshellarg($odsfile) , escapeshellarg($this->cibledir));
533 
534  system($cmd);
535  //rmdir($this->cibledir);
536  return '';
537  }
538 
539  protected function execute($appname, $actionargn)
540  {
541 
542  if ($this->action == "") return ("Layout not used in a core environment");
543  // analyse action & its args
544  $actionargn = str_replace(":", "--", $actionargn); //For buggy function parse_url in PHP 4.3.1
545  $acturl = parse_url($actionargn);
546  $actionname = $acturl["path"];
547 
548  global $ZONE_ARGS;
549  $OLD_ZONE_ARGS = $ZONE_ARGS;
550  if (isset($acturl["query"])) {
551  $acturl["query"] = str_replace("--", ":", $acturl["query"]); //For buggy function parse_url in PHP 4.3.1
552  $zargs = explode("&", $acturl["query"]);
553  foreach ($zargs as $k => $v) {
554  if (preg_match("/([^=]*)=(.*)/", $v, $regs)) {
555  // memo zone args for next action execute
556  $ZONE_ARGS[$regs[1]] = urldecode($regs[2]);
557  }
558  }
559  }
560 
561  if ($appname != $this->action->parent->name) {
562  $appl = new Application();
563  $appl->Set($appname, $this->action->parent);
564  } else {
565  $appl = & $this->action->parent;
566  }
567 
568  if (($actionname != $this->action->name) || ($OLD_ZONE_ARGS != $ZONE_ARGS)) {
569  $act = new Action();
570  $res = '';
571  if ($act->Exists($actionname, $appl->id)) {
572 
573  $act->Set($actionname, $appl);
574  } else {
575  // it's a no-action zone (no ACL, cannot be call directly by URL)
576  $act->name = $actionname;
577 
578  $res = $act->CompleteSet($appl);
579  }
580  if ($res == "") {
581  $res = $act->execute();
582  }
583  $ZONE_ARGS = $OLD_ZONE_ARGS; // restore old zone args
584  return ($res);
585  } else {
586  return ("Fatal loop : $actionname is called in $actionname");
587  }
588  }
589  /**
590  * set key/value pair assume key if XML fragment well formed
591  * @param string $tag the key to replace
592  * @param string|string[] $val the value for the key
593  */
594  public function set($tag, $val)
595  {
596  if (!isUTF8($val)) $val = utf8_encode($val);
597  if (!$this->isXml($val)) {
598  $this->pkey[$tag] = "[$tag]";
599  if (is_array($val)) $val = implode('<text:tab/>', $val);
600  $this->rkey[$tag] = $val;
601  } else {
602 
603  $this->rkeyxml[$tag] = $val;
604  }
605  }
606  /**
607  * set key/value pair and XML entity encode
608  * @param string $tag the key to replace
609  * @param string $val the value for the key
610  */
611  public function eSet($tag, $val)
612  {
613  $this->set($tag, $this->xmlEntities($val));
614  }
615  /**
616  * replace entities & < >
617  * @param string $s text to encode
618  * @return string
619  */
620  static public function xmlEntities($s)
621  {
622  return str_replace(array(
623  "&",
624  '<',
625  '>'
626  ) , array(
627  "&amp;",
628  '&lt;',
629  '&gt;'
630  ) , $s);
631  }
632  /**
633  *
634  * @param string $val
635  * @return bool
636  */
637  protected function isXML($val)
638  {
639  return false;
640  //return preg_match("/<text:/", $val);
641 
642  }
643  /**
644  * get value of $tag key
645  * @param string $tag
646  * @return string
647  */
648  public function get($tag)
649  {
650  if (isset($this->rkey)) return $this->rkey[$tag];
651  return "";
652  }
653  /**
654  * parse text
655  * @param string|null $out
656  */
657  protected function ParseText(&$out = null)
658  {
659  $this->template = preg_replace_callback('/\[TEXT(\([^\)]*\))?:([^\]]*)\]/', function ($matches)
660  {
661  $s = $matches[2];
662  if ($s == "") return $s;
663  if (!$matches[1]) {
664  return _($s);
665  } else {
666  return ___($s, trim($matches[1], '()'));
667  }
668  }
669  , $this->template);
670  }
671  /**
672  *
673  */
674  protected function updateManifest()
675  {
676  $manifest = new DomDocument();
677  $manifest->loadXML($this->manifest);
678  /*
679  * @var DOMDocument $manifest_root
680  */
681  $manifest_root = null;
682  $items = $manifest->childNodes;
683  /**
684  * @var $item DOMElement
685  */
686  foreach ($items as $item) {
687  if ($item->nodeName == 'manifest:manifest') {
688  $manifest_root = $item;
689  break;
690  }
691  }
692  if ($manifest_root === null) {
693  return false;
694  }
695 
696  $items = $manifest->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", "file-entry");
697  foreach ($items as $aItem) {
698  /**
699  * @var $aItem DOMElement
700  */
701  $type = $aItem->getAttribute("manifest:media-type");
702  if (substr($type, 0, 6) == "image/") {
703  $file = $aItem->getAttribute("manifest:full-path");
704  if (in_array($file, $this->removed_images)) {
705  $aItem->parentNode->removeChild($aItem);
706  }
707  }
708  }
709  foreach ($this->added_images as $image) {
710  $mime = getSysMimeFile($this->cibledir . '/' . $image);
711  $new = $manifest->createElement("manifest:file-entry");
712  $new->setAttribute("manifest:media-type", $mime);
713  $new->setAttribute("manifest:full-path", $image);
714  $manifest_root->appendChild($new);
715  }
716 
717  $this->manifest = $manifest->saveXML();
718  return true;
719  }
720  /**
721  * parse images
722  */
723  protected function parseHtmlDraw()
724  {
725  $draws = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "frame");
726  foreach ($draws as $draw) {
727  /**
728  * @var $draw DOMElement
729  */
730  $name = trim($draw->getAttribute('draw:name'));
731  if ($name === "htmlgraphic") {
732  $this->setHtmlDraw($draw);
733  }
734  }
735  }
736  /**
737  * set image from html fragment
738  * @param DOMElement $node
739  * @return string
740  */
741  protected function setHtmlDraw(DOMElement & $draw)
742  {
743 
744  $imgs = $draw->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "image");
745  $err = "";
746  if ($imgs->length > 0) {
747  /**
748  * @var $img DOMElement
749  */
750  $img = $imgs->item(0);
751 
752  $href = $img->getAttribute('xlink:href');
753  $fileInfo = new VaultFileInfo();
754 
755  if (preg_match('/^file\/([^\/]+)\/([0-9]+)/', $href, $reg)) {
756  $vid = $reg[2];
757  $docid = $reg[1];
758  $docimg = new_doc('', $docid, true);
759  if ($docimg->isAlive()) {
760  $err = $docimg->control("view");
761  if (!$err) {
762  $fileInfo = \Dcp\VaultManager::getFileInfo($vid);
763  } else {
764  $fileInfo->path = "Images/erreur.png";
765  }
766  } else {
767  $fileInfo->path = "Images/noimage.png";
768  }
769  } elseif (preg_match('/action=EXPORTFILE.*&docid=([^&]+).*&attrid=([a-z0_9_-]+).*index=([0-9-]+)/i', $href, $reg)) {
770 
771  $docid = $reg[1];
772  $attrid = $reg[2];
773  $index = intval($reg[3]);
774 
775  $docimg = new_doc('', $docid, true);
776  if ($docimg->isAlive()) {
777  $err = $docimg->control("view");
778  if (!$err) {
779  if ($index < 0) {
780  $fileValue = $docimg->getRawValue($attrid);
781  } else {
782  $fileValue = $docimg->getMultipleRawValues($attrid, '', $index);
783  }
784  $fileInfo = (Object)$docimg->getFileInfo($fileValue);
785  } else {
786  $fileInfo->path = "Images/erreur.png";
787  }
788  } else {
789  $fileInfo->path = "Images/noimage.png";
790  }
791  }
792  if ($fileInfo->path) {
793  $href = sprintf('Pictures/dcp%s', basename($fileInfo->path));
794  $img->setAttribute('xlink:href', $href);
795  $this->added_images[] = $href;
796  if (!is_dir($this->cibledir . '/Pictures')) {
797  mkdir($this->cibledir . '/Pictures');
798  }
799 
800  if (!copy($fileInfo->path, $this->cibledir . '/' . $href)) {
801  $err = "setHtmlDraw::file copy fail";
802  }
803  // print_r2($this->dom->saveXML());exit;
804 
805  }
806  }
807  return $err;
808  }
809  /**
810  * set image
811  * @param DOMElement $draw
812  * @param string $name
813  * @param string $file
814  * @return string
815  */
816  protected function setDraw(DOMElement & $draw, $name, $file)
817  {
818  if (strpos($file, '<text:tab') !== false) {
819  return 'muliple values : fail';
820  }
821  $imgs = $draw->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "image");
822  $err = "";
823  if ($imgs->length > 0) {
824  /**
825  * @var $img DOMElement
826  */
827  $img = $imgs->item(0);
828  if (file_exists($file)) {
829  $draw->setAttribute('draw:name', substr($name, 2) . ' ' . uniqid() . mt_rand(1000, 9999));
830  $href = 'Pictures/dcp' . uniqid() . mt_rand(1000000, 9999999) . substr($img->getAttribute('xlink:href') , -9);
831  $img->setAttribute('xlink:href', $href);
832  $this->added_images[] = $href;
833  if (!copy($file, $this->cibledir . '/' . $href)) {
834  $err = "copy fail";
835  }
836 
837  if ($err == "") { // need to respect image proportion
838  $width = $draw->getAttribute('svg:width');
839  $size = getimagesize($file);
840  $unit = "";
841  if (preg_match('/[0-9\.]+(.*)$/', $width, $reg)) $unit = $reg[1];
842  $height = sprintf("%.03f%s", (doubleval($width) / $size[0]) * $size[1], $unit);
843  $draw->setAttribute('svg:height', $height);
844  }
845  }
846  }
847  return $err;
848  }
849  /**
850  * parse images
851  */
852  protected function parseDraw()
853  {
854  $draws = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "frame");
855 
856  foreach ($draws as $draw) {
857  /**
858  * @var $draw DOMElement
859  */
860 
861  $name = trim($draw->getAttribute('draw:name'));
862  if (preg_match('/\[(V_[A-Z0-9_-]+)\]/', $name, $reg)) {
863  $key = $reg[1];
864  if (isset($this->rkey[$key])) {
865  $this->setDraw($draw, $key, $this->rkey[$key]);
866  }
867  }
868  }
869  }
870  /**
871  * remove all xml:id attributes in children nodes
872  * @param DomNode $objNode
873  */
874  protected function removeXmlId(&$objNode)
875  {
876  $objNodeListNested = $objNode->childNodes;
877  foreach ($objNodeListNested as $objNodeNested) {
878  /**
879  * @var $objNodeNested DOMElement
880  */
881  if ($objNodeNested->nodeType == XML_ELEMENT_NODE) {
882  $objNodeNested->removeAttribute("xml:id");
883  $this->removeXmlId($objNodeNested);
884  }
885  }
886  }
887  /**
888  * This function replaces a node's string content with strNewContent
889  * @param DomNode $objNode
890  * @param string $strOldContent
891  * @param string $strNewContent
892  * @throws \Dcp\Exception
893  */
894  protected function replaceNodeText(DOMNode & $objNode, $strOldContent, $strNewContent)
895  {
896  if ($strNewContent === null) return;
897  if (is_array($strNewContent)) {
898  throw new Dcp\Exception("node replacement must be a string : array found");
899  }
900  $objNodeListNested = & $objNode->childNodes;
901  foreach ($objNodeListNested as $objNodeNested) {
902  /**
903  * @var $objNodeNested DOMElement
904  */
905  if ($objNodeNested->nodeType == XML_TEXT_NODE) {
906  if ($objNodeNested->nodeValue != "") {
907  if (strpos($strNewContent, '<text:p>') !== false) {
908  $strNewContent = str_replace('<', '--Lower.Than--', $strNewContent);
909  $strNewContent = str_replace('>', '--Greater.Than--', $strNewContent);
910  $strNewContent = htmlspecialchars_decode($strNewContent);
911  }
912  $objNodeNested->nodeValue = str_replace($strOldContent, $strNewContent, $objNodeNested->nodeValue);
913  }
914  } elseif ($objNodeNested->nodeType == XML_ELEMENT_NODE) {
915  if ($objNodeNested->nodeName == 'text:text-input') {
916  $name = $objNodeNested->getAttribute('text:description');
917  if ($name == $strOldContent) {
918  $this->setInputField($objNodeNested, substr($name, 1, -1) , $strNewContent);
919  }
920  } elseif ($objNodeNested->nodeName == 'text:drop-down') {
921  $name = $objNodeNested->getAttribute('text:name');
922  if ($name == $strOldContent) {
923  $this->setDropDownField($objNodeNested, substr($name, 1, -1) , $strNewContent);
924  }
925  } elseif ($objNodeNested->nodeName == 'draw:frame') {
926  $name = $objNodeNested->getAttribute('draw:name');
927  if (substr($name, 0, strlen($strOldContent)) == $strOldContent) {
928  $this->setDraw($objNodeNested, substr($strOldContent, 1, -1) , $strNewContent);
929  }
930  } else {
931  $this->replaceNodeText($objNodeNested, $strOldContent, $strNewContent);
932  }
933  }
934  }
935  }
936  /**
937  * parse bullet lists
938  */
939  protected function parseListItem()
940  {
941  $err = '';
942  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "list");
943  foreach ($lists as $list) {
944  /**
945  * @var $list DOMElement
946  */
947  $items = $list->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "list-item");
948  if ($items->length > 0) {
949  $item = $items->item(0);
950  $skey = implode('|', array_keys($this->arrayMainKeys));
951  if (preg_match_all("/\[($skey)\]/", $this->innerXML($list) , $reg)) {
952  $reg0 = $reg[0];
953  $tvkey = array();
954  $maxk = 0;
955  foreach ($reg0 as $k => $v) {
956  $key = substr(trim($v) , 1, -1);
957  $tvkey[$key] = $this->arrayMainKeys[$key];
958  $maxk = max(count($tvkey[$key]) , $maxk);
959  }
960  if ($maxk > 0) {
961  for ($i = 0; $i < $maxk; $i++) {
962  $clone = $item->cloneNode(true);
963  $item->parentNode->appendChild($clone);
964  foreach ($tvkey as $kk => $key) {
965  $this->replaceNodeText($clone, "[$kk]", $key[$i]);
966  }
967  }
968  }
969  $item->parentNode->removeChild($item);
970  }
971  }
972  }
973  return $err;
974  }
975 
976  private function _section_cmp($k1, $k2)
977  {
978  if ($k2 > $k1) return 1;
979  else if ($k2 < $k1) return -1;
980  return 0;
981  }
982  /**
983  * parse section repeat
984  */
985  protected function parseSection()
986  {
987 
988  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "section");
989  $ks = 0;
990  $section = array();
991  // need to inpect section with max depth before to avoid et repeat top level section
992 
993  /**
994  * @var $aSection DOMElement
995  */
996  foreach ($lists as $aSection) {
997  $depth = $this->getNodeDepth($aSection);
998  $section[($depth * 200) + $ks] = $aSection;
999  $ks++;
1000  }
1001  //reorder by depth
1002  uksort($section, array(
1003  $this,
1004  "_section_cmp"
1005  ));
1006  foreach ($section as $aSection) {
1007  /**
1008  * @var $aSection DOMElement
1009  */
1010  $skey = implode('|', array_keys($this->arrayMainKeys));
1011  if (preg_match_all("/\\[($skey)\\]/", $this->innerXML($aSection) , $reg)) {
1012  $reg0 = $reg[0];
1013  $tvkey = array();
1014  $maxk = 0;
1015  foreach ($reg0 as $k => $v) {
1016  $key = substr(trim($v) , 1, -1);
1017  $tvkey[$key] = $this->arrayMainKeys[$key];
1018  $maxk = max(count($tvkey[$key]) , $maxk);
1019  }
1020  if ($maxk > 0) {
1021  for ($i = 0; $i < $maxk; $i++) {
1022  /*
1023  * @var DOMElement $clone
1024  */
1025  $clone = $aSection->cloneNode(true);
1026  $aSection->parentNode->insertBefore($clone, $aSection);
1027  foreach ($tvkey as $kk => $key) {
1028  $this->replaceNodeText($clone, "[$kk]", $key[$i]);
1029  }
1030  $this->replaceRowIf($clone, array(
1031  $i
1032  )); // main level
1033  $this->replaceRowNode($clone, array(
1034  $i
1035  )); // inspect sub levels
1036 
1037  }
1038  }
1039  $aSection->parentNode->removeChild($aSection);
1040  }
1041  }
1042  }
1043  /**
1044  * modify a text:input field value
1045  *
1046  * @param DomElement $node
1047  * @param string $name
1048  * @param string $value
1049  * @return string error
1050  */
1051  protected function setInputField(DomElement & $node, $name, $value)
1052  {
1053  if (strpos($value, '<text:tab') !== false) {
1054  return 'muliple values : fail';
1055  }
1056 
1057  $node->nodeValue = $value;
1058  $node->setAttribute("text:description", '[PP' . $name . 'PP]');
1059  return '';
1060  }
1061  /**
1062  * modify a text:drop-down list
1063  *
1064  * @param DOMElement $node
1065  * @param string $name
1066  * @param string $value
1067  * @return string error message
1068  */
1069  protected function setDropDownField(DOMElement & $node, $name, $value)
1070  {
1071  if (strpos($value, '<text:tab') !== false) {
1072  return 'muliple values : fail';
1073  }
1074  $this->removeAllChilds($node);
1075  $node->setAttribute("text:name", '[PP' . $name . 'PP]');
1076  $value = str_replace(array(
1077  "&lt;",
1078  "&gt;",
1079  "&amp;"
1080  ) , array(
1081  "<",
1082  ">",
1083  '&'
1084  ) , $value);
1085  $item = new DOMElement('text:label', '', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0');
1086  $item = $node->appendChild($item);
1087  /**
1088  * @var $item DOMElement
1089  */
1090  $item->setAttribute("text:current-selected", 'true');
1091  $item->setAttribute("text:value", $value);
1092  $node->appendChild(new DOMText($value));
1093  return '';
1094  }
1095  /**
1096  * remove all child nodes
1097  *
1098  * @param DomNode $objNode
1099  */
1100  protected function removeAllChilds(DOMNode & $objNode)
1101  {
1102  $objNodeListNested = $objNode->childNodes;
1103  $objNode->nodeValue = '';
1104  if (!empty($objNodeListNested) && $objNodeListNested->length > 0) {
1105  foreach ($objNodeListNested as $objNodeNested) {
1106  $objNode->removeChild($objNodeNested);
1107  }
1108  }
1109  }
1110  /**
1111  * parse tables
1112  */
1113  protected function parseTableRow()
1114  {
1115  $err = '';
1116  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0", "table-row");
1117  $validRow = array();
1118 
1119  $skey = implode('|', array_keys($this->arrayMainKeys));
1120  /**
1121  * @var $rowItem DOMElement
1122  */
1123  foreach ($lists as $rowItem) {
1124  if (preg_match("/\[($skey)\]/", $this->innerXML($rowItem) , $reg)) {
1125  $validRow[] = $rowItem;
1126  }
1127  }
1128  foreach ($validRow as $rowItem) {
1129  /**
1130  * @var $rowItem DOMElement
1131  */
1132  if (preg_match_all("/\[($skey)\]/", $this->innerXML($rowItem) , $reg)) {
1133  $reg0 = $reg[0];
1134  $tvkey = array();
1135  $maxk = 0; // search values which has the greatest number of values
1136  foreach ($reg0 as $k => $v) {
1137  $key = substr(trim($v) , 1, -1);
1138  $tvkey[$key] = $this->arrayMainKeys[$key];
1139  $maxk = max(count($tvkey[$key]) , $maxk);
1140  }
1141  if ($maxk > 0) {
1142  for ($i = 0; $i < $maxk; $i++) {
1143  /*
1144  * @var DOMElement $clone
1145  */
1146  $clone = $rowItem->cloneNode(true);
1147 
1148  $rowItem->parentNode->insertBefore($clone, $rowItem);
1149  foreach ($tvkey as $kk => $key) {
1150  $this->replaceNodeText($clone, "[$kk]", $key[$i]);
1151  }
1152  $this->replaceRowIf($clone, array(
1153  $i
1154  )); // main level
1155  $this->replaceRowNode($clone, array(
1156  $i
1157  )); // inspect sub levels
1158 
1159  }
1160  }
1161 
1162  $rowItem->parentNode->removeChild($rowItem);
1163  }
1164  }
1165  return $err;
1166  }
1167  /**
1168  * return the number of array in arrays
1169  * @param array $v
1170  * @return int
1171  */
1172  private static function getArrayDepth($v)
1173  {
1174  $depth = - 1;
1175  while (is_array($v)) {
1176  $depth++;
1177  $v = current($v);
1178  }
1179  return $depth;
1180  }
1181  /**
1182  *
1183  * Retrieve one of values for a multi value key
1184  * @param string $key the key name (multiple values)
1185  * @param array $levelPath path to access of a particular value
1186  * @return string|null
1187  */
1188  protected function getArrayKeyValue($key, array $levelPath)
1189  {
1190  $value = null;
1191 
1192  if (count($levelPath) == 1) {
1193  if (isset($this->arrayMainKeys[$key])) {
1194  $index = current($levelPath);
1195  return $this->arrayMainKeys[$key][$index];
1196  }
1197  }
1198  if (!isset($this->arrayKeys[$key])) return null;
1199 
1200  $value = $this->arrayKeys[$key];
1201  foreach ($levelPath as $index) {
1202  $value = $value[$index];
1203  }
1204 
1205  return $value;
1206  }
1207  /**
1208  * fix span cause when IF/ENDIF are not on the same depth
1209  * @param $s
1210  */
1211  private function fixSpanIf(&$s)
1212  {
1213  $s = preg_replace('/<text:span ([^>]*)>\s*<\/text:p>/s', "</text:p>", $s);
1214  $s = preg_replace('/<text:p ([^>]*)>\s*<\/text:span>/s', "<text:p \\1>", $s);
1215  }
1216  /**
1217  *
1218  * Inspect conditions in cells
1219  * @param DOMNode $row
1220  * @param array $levelPath
1221  */
1222  protected function replaceRowIf(DOMNode & $row, array $levelPath)
1223  {
1224 
1225  $this->removeXmlId($row);
1226 
1227  $inner = $row->ownerDocument->saveXML($row);
1228 
1229  $head = '<?xml version="1.0" encoding="UTF-8"?><office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0">';
1230  $foot = '</office:document-content>';
1231 
1232  $level = 0;
1233  while ($level < 10) {
1234  $replacement = preg_replace_callback('/(?m)\[IF(NOT)?\s*([^\]]*)\](.*?)\[ENDIF\s*\\2\]/s', function ($matches) use ($levelPath)
1235  {
1236  return $this->TestIf($matches[2], $matches[3], $matches[1], $levelPath);
1237  }
1238  , $inner);
1239  if ($inner == $replacement) break;
1240  else $inner = $replacement;
1241  $level++;
1242  }
1243  $this->fixSpanIf($replacement);
1244 
1245  $dxml = new DomDocument();
1246 
1247  $dxml->loadXML($head . $replacement . $foot);
1248  $ot = $dxml->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "document-content");
1249  if ($ot->length > 0) {
1250  $newnode = $this->dom->importNode($ot->item(0)->firstChild, true);
1251  // copy inside
1252  // first delete inside
1253  while ($row->firstChild) {
1254  $row->removeChild($row->firstChild);
1255  }
1256  // move to
1257  while ($newnode->firstChild) {
1258  $row->appendChild($newnode->firstChild);
1259  }
1260  }
1261  }
1262  /**
1263  * @param DOMElement $row
1264  * @param array $levelPath
1265  */
1266  protected function replaceRowNode(DOMElement & $row, array $levelPath)
1267  {
1268  // Inspect sub tables, rows
1269  $this->replaceRowSomething($row, $levelPath, "table", "table-row", true);
1270  // Inspect list in sub tables
1271  $this->replaceRowSomething($row, $levelPath, "text", "list-item", false);
1272  // Inspect list in subsection
1273  $this->replaceRowSomething($row, $levelPath, "text", "section", true);
1274  }
1275  /**
1276  *
1277  * Inspect list in sub tables
1278  * @param DOMElement $row
1279  * @param array $levelPath
1280  * @param string $ns namespace for filter items (like text or table)
1281  * @param string $tag tag for filter (like table-row or list-item)
1282  * @param boolean $recursive recursive mode
1283  */
1284  protected function replaceRowSomething(DOMElement & $row, array $levelPath, $ns, $tag, $recursive)
1285  {
1286  if (count($this->arrayKeys) == 0) return; // nothing to do
1287  $keys = array();
1288  $subIndex = count($levelPath);
1289  foreach ($this->arrayKeys as $k => $v) {
1290  if ($this->getArrayDepth($v) == $subIndex) $keys[] = $k;
1291  }
1292 
1293  $rowList = $row->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:$ns:1.0", $tag);
1294  if ($rowList->length > 0) {
1295  $skey = implode('|', $keys);
1296  /* print "<h1>$tag</h1>";
1297  print_r2($levelPath);
1298  print_r2($keys);*/
1299  $tvkey = array();
1300  foreach ($rowList as $item) {
1301  /**
1302  * @var $item DOMElement
1303  */
1304  if (preg_match_all("/\\[($skey)\\]/", $this->innerXML($item) , $reg)) {
1305 
1306  $maxk = 0;
1307  foreach ($reg[1] as $k => $v) {
1308  $vkey = $this->getArrayKeyValue($v, $levelPath);
1309  $tvkey[$v] = $vkey;
1310  $maxk = max(count($tvkey[$v]) , $maxk);
1311  }
1312 
1313  if ($maxk > 0) {
1314  for ($i = 0; $i < $maxk; $i++) {
1315  /*
1316  * @var DOMElement $clone
1317  */
1318  $clone = $item->cloneNode(true);
1319  $item->parentNode->insertBefore($clone, $item);
1320  foreach ($tvkey as $kk => $key) {
1321  $this->replaceNodeText($clone, "[$kk]", $key[$i]);
1322  }
1323  $newPath = array_merge($levelPath, array(
1324  $i
1325  ));
1326  $this->replaceRowIf($clone, $newPath);
1327  //if ($recursive) $this->replaceRowSomething($clone,$newPath,$ns,$tag,$recursive);
1328  if ($recursive) $this->replaceRowNode($clone, $newPath);
1329  }
1330  }
1331  $item->parentNode->removeChild($item);
1332  }
1333  }
1334  }
1335  }
1336  /**
1337  * parse text:input
1338  */
1339  protected function parseInput()
1340  {
1341  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "text-input");
1342  foreach ($lists as $list) {
1343  /**
1344  * @var $list DOMElement
1345  */
1346  $name = $list->getAttribute("text:description");
1347  if (preg_match('/\[(V_[A-Z0-9_-]+)\]/', $name, $reg)) {
1348  $key = $reg[1];
1349  if (isset($this->rkey[$key])) {
1350  $this->setInputField($list, $key, $this->rkey[$key]);
1351  }
1352  }
1353  }
1354  }
1355  /**
1356  * parse text:drop-down
1357  */
1358  protected function parseDropDown()
1359  {
1360  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "drop-down");
1361  foreach ($lists as $list) {
1362  /**
1363  * @var $list DOMElement
1364  */
1365  $name = $list->getAttribute("text:name");
1366  if (preg_match('/\[(V_[A-Z0-9_-]+)\]/', $name, $reg)) {
1367  $key = $reg[1];
1368  if (isset($this->rkey[$key])) {
1369  $this->setDropDownField($list, $key, $this->rkey[$key]);
1370  }
1371  }
1372  }
1373  }
1374  /**
1375  * restore protected values
1376  */
1377  protected function restoreProtectedValues()
1378  {
1379  $this->template = preg_replace('/\[PP(V_[A-Z0-9_]+)PP\]/s', '[$1]', $this->template);
1380  $this->template = str_replace('--Lower.Than--', '<', $this->template);
1381  $this->template = str_replace('--Greater.Than--', '>', $this->template);
1382  }
1383  /**
1384  * parse section and clone "tpl_xxx" sections into saved_sections
1385  */
1386  protected function parseTplSection()
1387  {
1388  $this->saved_sections = array();
1389  // remove old generated sections
1390  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "section");
1391  foreach ($lists as $list) {
1392  /**
1393  * @var $list DOMElement
1394  */
1395  $name = $list->getAttribute("text:name");
1396  if (substr($name, 0, 5) == '_tpl_') {
1397  $list->parentNode->removeChild($list);
1398  }
1399  }
1400  // clone sections and generate them again
1401  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "section");
1402  foreach ($lists as $list) {
1403  /**
1404  * @var $list DOMElement
1405  */
1406  $name = $list->getAttribute("text:name");
1407  if (substr($name, 0, 4) == 'tpl_') {
1408  $this->removeXmlId($list);
1409  // restore original style name of first head
1410  $heads = $list->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "h");
1411  if ($heads->length > 0) {
1412  /**
1413  * @var $firsthead DOMElement
1414  */
1415  $firsthead = $heads->item(0);
1416  $firsthead->setAttribute("text:style-name", trim($firsthead->getAttribute('text:style-name') , '_'));
1417  }
1418  $this->saved_sections[$name] = $list->cloneNode(true);
1419  /**
1420  * @var $originSection DOMElement
1421  */
1422  $originSection = $this->saved_sections[$name];
1423  $list->setAttribute("text:name", '_' . $name);
1424  $list->setAttribute("text:protected", 'true');
1425  $list->setAttribute("text:display", 'true');
1426  // // special treatment to have correct chapter numeration search first header
1427  $heads = $originSection->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "h");
1428  if ($heads->length > 0) {
1429  /**
1430  * @var $firsthead DOMElement
1431  */
1432  $firsthead = $heads->item(0);
1433  $styleName = $firsthead->getAttribute("text:style-name");
1434  if ($styleName) {
1435  $styleName = trim($styleName, '_');
1436  $styles = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:style:1.0", "style");
1437  //addLogMsg(array("style"=>$styleName,"length"=>$styles->length));
1438  $tStyleName = array();
1439  foreach ($styles as $style) {
1440  /**
1441  * @var $style DOMElement
1442  */
1443  $aStyleName = $style->getAttribute("style:name");
1444  $tStyleName[] = $aStyleName;
1445  if ($aStyleName == $styleName) {
1446  $copyName = '_' . $styleName . '_';
1447  if (!(in_array($copyName, $tStyleName))) {
1448  /**
1449  * @var $cloneStyle DOMElement
1450  */
1451  $cloneStyle = $style->cloneNode(true);
1452  $cloneStyle->setAttribute("style:name", $copyName);
1453  $cloneStyle->setAttribute("style:list-style-name", ""); // unset numeration chapter
1454  $style->parentNode->insertBefore($cloneStyle, $style);
1455  }
1456  $firsthead->setAttribute("text:style-name", $copyName);
1457  break;
1458  }
1459  }
1460  }
1461  }
1462  }
1463  }
1464  }
1465  /**
1466  * restore cloned and saved sections at the end
1467  */
1468  protected function restoreSection()
1469  {
1470 
1471  $inserts_to_do = array();
1472 
1473  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "section");
1474  foreach ($lists as $list) {
1475  /**
1476  * @var $list DOMElement
1477  */
1478  $name = $list->getAttribute("text:name");
1479  if (substr($name, 0, 5) == '_tpl_' && isset($this->saved_sections[substr($name, 1) ])) {
1480  $node = $this->dom->importNode($this->saved_sections[substr($name, 1) ], true);
1481  $inserts_to_do[] = array(
1482  $node,
1483  $list
1484  );
1485  }
1486  }
1487  foreach ($inserts_to_do as $insert_to_do) {
1488  //$node = $insert_to_do[1]->parentNode->insertBefore($insert_to_do[0], $insert_to_do[1]);
1489  // insert after
1490  if ($insert_to_do[1]->nextSibling) {
1491  /** @noinspection PhpUndefinedMethodInspection */
1492  $node = $insert_to_do[1]->parentNode->insertBefore($insert_to_do[0], $insert_to_do[1]->nextSibling);
1493  } else {
1494  /** @noinspection PhpUndefinedMethodInspection */
1495  $node = $insert_to_do[1]->parentNode->appenChild($insert_to_do[0]);
1496  }
1497  /**
1498  * @var $node DOMElement
1499  */
1500  $node->setAttribute("text:protected", 'true');
1501  $node->setAttribute("text:display", 'none');
1502  }
1503  }
1504  /**
1505  * Initialize of list to be used in table or list
1506  * @param string $key the key variable
1507  * @param array $t the values of the key
1508  */
1509  public function setColumn($key, array $t)
1510  {
1511  $ti = array();
1512  $k = 0;
1513  foreach ($t as $v) $ti[$k++] = $v; // delete associative keys
1514  if (is_array(current($t))) $this->setArray($key, $ti);
1515  else $this->arrayMainKeys[$key] = $ti;
1516  //else $this->set($key,implode('<text:tab/>',$t));
1517 
1518  }
1519 
1520  protected function setArray($key, array $t)
1521  {
1522  if (!$key) throw new Dcp\Exception('Key must not be empty');
1523  $this->arrayKeys[$key] = $t;
1524  }
1525  /**
1526  * @deprecated BLOCK not supported, use setColumn instead
1527  * @param string $p_nom_block
1528  * @param array $data
1529  */
1530  public function setBlockData($p_nom_block, $data = NULL)
1531  {
1532  deprecatedFunction();
1533  if ($p_nom_block != "") {
1534  if ($data != null && $this->encoding == "utf-8") {
1535  if (is_array($data)) {
1536  foreach ($data as $k => $v) {
1537  foreach ($v as $kk => $vk) {
1538  if (!isUTF8($vk)) {
1539  $data[$k][$kk] = utf8_encode($vk);
1540  }
1541  }
1542  }
1543  } else {
1544  if (!isUTF8($data)) $data = utf8_encode($data);
1545  }
1546  }
1547  $this->data[$p_nom_block] = $data;
1548  if (is_array($data)) {
1549  reset($data);
1550  $elem = current($data);
1551  if (isset($elem) && is_array($elem)) {
1552  reset($elem);
1553  foreach ($elem as $k => $v) {
1554  if (!isset($this->corresp["$p_nom_block"]["[$k]"])) {
1555  $this->setBlockCorresp($p_nom_block, $k);
1556  }
1557  }
1558  }
1559  }
1560  } else {
1561  $this->setrepeatable($data);
1562  }
1563  }
1564  /*
1565  * set array to be use in repeat set like table, list-item or section
1566  * @param array $data the arry to set
1567  */
1568  public function setrepeatable(array $data)
1569  {
1570 
1571  $t = array();
1572  if (is_array($data)) {
1573  foreach ($data as $k => $v) {
1574  foreach ($v as $ki => $vi) {
1575  $t[$ki][$k] = $vi;
1576  }
1577  }
1578  }
1579  // fill array
1580  $max = 0;
1581  foreach ($t as $k => $v) {
1582  if (count($v) > $max) $max = count($v);
1583  }
1584  foreach ($t as $k => $v) {
1585  if (count($v) < $max) {
1586  $fill = array_fill(0, $max, '');
1587  foreach ($v as $idx => $vi) {
1588  $fill[$idx] = $vi;
1589  }
1590  $t[$k] = $fill;
1591  }
1592  }
1593  // affect completed columns
1594  foreach ($t as $k => $v) {
1595  $this->setColumn($k, $v);
1596  }
1597  }
1598 
1599  protected function addHTMLStyle()
1600  {
1601  $xmldata = '<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">' . "</xhtml:html>";
1602 
1603  $ddXsl = new DOMDocument();
1604  $ddXsl->load(DEFAULT_PUBDIR . "/CORE/Layout/html2odt.xsl");
1605  $xslt = new xsltProcessor;
1606 
1607  $xslt->importStyleSheet($ddXsl);
1608 
1609  $ddData = new DOMDocument();
1610  $ddData->loadXML($xmldata);
1611  $xmlout = $xslt->transformToXML($ddData);
1612 
1613  $dxml = new DomDocument();
1614  $dxml->loadXML($xmlout);
1615  $ot = $dxml->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "automatic-styles");
1616  if ($ot->length <= 0) {
1617  $this->addError("LAY0008", DEFAULT_PUBDIR . "/CORE/Layout/html2odt.xsl");
1618  $this->exitError();
1619  }
1620  $ot1 = $ot->item(0);
1621  $ass = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "automatic-styles");
1622  if ($ass->length <= 0) {
1623  $outfile = uniqid(getTmpDir() . "/oooKo") . '.xml';
1624  file_put_contents($outfile, $this->template);
1625  $this->addError("LAY0009", $this->file);
1626  $this->exitError($outfile);
1627  }
1628  $ass0 = $ass->item(0);
1629  foreach ($ot1->childNodes as $ots) {
1630  $c = $this->dom->importNode($ots, true);
1631  $ass0->appendChild($c);
1632  }
1633  }
1634  /**
1635  * Delete not used images (need when reuse template where repeat section)
1636  */
1637  protected function removeOrphanImages()
1638  {
1639  $imgs = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "image");
1640  $used_images = array();
1641  foreach ($imgs as $img) {
1642  /**
1643  * @var $img DOMElement
1644  */
1645  $href = basename($img->getAttribute('xlink:href'));
1646  if (substr($href, 0, 7) == 'dcp') {
1647  $used_images[] = $href;
1648  }
1649  }
1650  $files = glob($this->cibledir . '/Pictures/dcp*');
1651  if (is_array($files)) {
1652  foreach ($files as $file) {
1653  if (!in_array(basename($file) , $used_images)) {
1654  $this->removed_images[] = 'Pictures/' . basename($file);
1655  @unlink($file);
1656  }
1657  }
1658  }
1659  }
1660 
1661  protected function GenJsRef()
1662  {
1663  return "";
1664  }
1665 
1666  public function GenJsCode($showlog, $onlylog = false)
1667  {
1668  return ("");
1669  }
1670 
1671  protected function ParseJs(&$out)
1672  {
1673  }
1674 
1675  protected function GenCssRef($oldCompatibility = true)
1676  {
1677  return "";
1678  }
1679 
1680  protected function GenCssCode()
1681  {
1682  return ("");
1683  }
1684 
1685  protected function ParseCss(&$out)
1686  {
1687  }
1688  /**
1689  * generate OOo document style part
1690  */
1691  protected function genStyle()
1692  {
1693 
1694  $this->dom = new DOMDocument();
1695 
1696  $this->dom->loadXML($this->style_template);
1697  if ($this->dom) {
1698  $this->template = $this->style_template;
1699 
1700  $this->parseDraw();
1701  $this->template = $this->dom->saveXML();
1702 
1703  $this->hideUserFieldSet();
1704  $this->ParseIf();
1705  $this->ParseKey();
1706  $this->ParseText();
1707  $this->restoreUserFieldSet();
1708  $this->style_template = $this->template;
1709  }
1710  }
1711  /**
1712  * generate OOo document meta part
1713  */
1714  protected function genMeta()
1715  {
1716  $this->dom = new DOMDocument();
1717 
1718  $this->dom->loadXML($this->meta_template);
1719  if ($this->dom) {
1720  $this->template = $this->meta_template;
1721 
1722  $this->ParseIf();
1723  $this->ParseKey();
1724  $this->ParseText();
1725 
1726  $this->meta_template = $this->template;
1727  }
1728  }
1729  /**
1730  * clean section done by htmltext values
1731  * delete unecessary span or p
1732  * delete section tag if needed (not in cell or text:section or text:body
1733  */
1734  protected function parseHtmlText()
1735  {
1736  $this->dom->loadXML($this->template);
1737  $lists = $this->dom->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "section");
1738  $htmlSections = array();
1739  $htmlCleanSections = array();
1740  foreach ($lists as $list) {
1741  /**
1742  * @var $list DOMElement
1743  */
1744  $aid = $list->getAttribute("aid");
1745  if ($aid) {
1746  if ($list->parentNode->childNodes->length == 1) {
1747  $htmlSections[] = $list;
1748  } else {
1749  // remove section
1750  $htmlCleanSections[] = $list;
1751  }
1752  $list->removeAttribute("aid");
1753  }
1754  }
1755  foreach ($htmlSections as $htmlSection) {
1756  /**
1757  * @var $htmlSection DOMElement
1758  */
1759  $pParentHtml = $htmlSection->parentNode->parentNode;
1760  $parentHtml = $htmlSection->parentNode;
1761 
1762  if ($parentHtml->nextSibling) {
1763  $pParentHtml->insertBefore($htmlSection, $parentHtml->nextSibling);
1764  } else {
1765  $pParentHtml->appendChild($htmlSection);
1766  }
1767  $pParentHtml->removeChild($parentHtml);
1768  // double up
1769  $pParentHtml = $htmlSection->parentNode->parentNode;
1770  $parentHtml = $htmlSection->parentNode;
1771 
1772  if (($parentHtml->nodeName == "text:p") && ($parentHtml->childNodes->length == 1)) {
1773  $htmlPs = $htmlSection->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0", "p");
1774  /*
1775  * @var DOMElement $p
1776  */
1777  foreach ($htmlPs as $p) {
1778  foreach ($parentHtml->attributes as $attribute) {
1779 
1780  $p->setAttribute('text:' . $attribute->name, $attribute->value);
1781  }
1782  }
1783 
1784  if ($parentHtml->nextSibling) {
1785  $pParentHtml->insertBefore($htmlSection, $parentHtml->nextSibling);
1786  } else {
1787  $pParentHtml->appendChild($htmlSection);
1788  }
1789 
1790  $pParentHtml->removeChild($parentHtml);
1791 
1792  if (in_array($htmlSection->parentNode->nodeName, array(
1793  "text:list-item",
1794  // "draw:text-box",
1795  // "text:p"
1796 
1797  ))) {
1798  $htmlCleanSections[] = $htmlSection;
1799  $attrid = substr($htmlSection->getAttribute("text:name") , 7);
1800  $this->addError("LAY0002", "[V_" . strtoupper($attrid) . "]");
1801  }
1802  //print "Parent Node is ".$htmlSection->parentNode->nodeName."\n";
1803 
1804  } else {
1805  if (!in_array($parentHtml->nodeName, array(
1806  'office:text',
1807  'text:text-content',
1808  'text:office-text-content-main',
1809  'table:table-cell',
1810  'draw:text-box'
1811  ))) {
1812  $htmlCleanSections[] = $htmlSection;
1813  $attrid = substr($htmlSection->getAttribute("text:name") , 7);
1814  $this->addError("LAY0005", "[V_" . strtoupper($attrid) . "]");
1815  }
1816  }
1817  }
1818  foreach ($htmlCleanSections as $htmlSection) {
1819  /**
1820  * @var $htmlSection DOMElement
1821  */
1822 
1823  $attrid = substr($htmlSection->getAttribute("text:name") , 7);
1824 
1825  $pp = $this->dom->createElement("text:span");
1826  $pp->nodeValue = "HTML attribute misplaced : " . "[V_" . strtoupper($attrid) . "]";
1827  $htmlSection->parentNode->appendChild($pp);
1828  }
1829 
1830  $this->parseHtmlDraw();
1831  $this->template = $this->dom->saveXML();
1832  }
1833  /**
1834  * get all error stored by addError
1835  * @return string
1836  */
1837  public function getErrors()
1838  {
1839  $s = array();
1840  foreach ($this->errors as $err) {
1841  $s[] = ErrorCode::getError($err["code"], $err["key"]);
1842  }
1843  return implode("\n", $s);
1844  }
1845  /**
1846  * send exception and exit generation
1847  * use sored error
1848  * @see addError()
1849  * @param string $outfile corrupted file path
1850  * @throws Dcp\Layout\Exception
1851  */
1852  protected function exitError($outfile = '')
1853  {
1854  foreach ($this->errors as $err) {
1855  if ($err["code"]) {
1856  $e = new Dcp\Layout\Exception($err["code"], $err["key"]);
1857  if ($outfile) {
1858  error_log(sprintf("Error {%s}: corrupted temporary file is %s", $err["code"], $outfile));
1859  $e->setCorruptedFile($outfile);
1860  }
1861  throw $e;
1862  }
1863  }
1864  }
1865  /**
1866  * store an error code
1867  * @param string $code
1868  * @param string $key
1869  * @param string $message
1870  */
1871  protected function addError($code, $key, $message = '')
1872  {
1873  $this->errors[] = array(
1874  "key" => $key,
1875  "code" => $code,
1876  "message" => $message
1877  );
1878  }
1879  /**
1880  * Change Element Name
1881  * @param DOMElement $node
1882  * @param string $name
1883  * @return DOMElement
1884  */
1885  protected function changeElementName($node, $name)
1886  {
1887 
1888  $newElement = $this->dom->createElement($name);
1889  // Clone the attributes:
1890  foreach ($node->attributes as $attribute) {
1891 
1892  $newElement->setAttribute($attribute->name, $attribute->value);
1893  }
1894  // Add clones of the old element's children to the replacement
1895 
1896  /*
1897  * @var DOMElement $child
1898  */
1899  foreach ($node->childNodes as $child) {
1900 
1901  $newElement->appendChild($child->cloneNode(true));
1902  }
1903  // Replace the old node
1904  $node->parentNode->replaceChild($newElement, $node);
1905  return $newElement;
1906  }
1907  /**
1908  * generate OOo document content
1909  */
1910  protected function genContent()
1911  {
1912 
1913  $this->dom = new DOMDocument();
1914 
1915  $this->dom->loadXML($this->content_template);
1916  if ($this->dom) {
1917  $this->template = $this->content_template;
1918 
1919  $this->parseTplSection();
1920  //header('Content-type: text/xml; charset=utf-8');print $this->dom->saveXML();exit;
1921  $this->hideUserFieldSet();
1922  $this->parseTableRow();
1923 
1924  $this->parseSection();
1925  $this->parseListItem();
1926  $this->parseDraw();
1927 
1928  $this->parseInput();
1929  $this->parseDropDown();
1930 
1931  $this->addHTMLStyle();
1932  $this->template = $this->dom->saveXML();
1933  // Parse i18n text
1934  $this->ParseBlock();
1935  $this->ParseIf();
1936  //$this->ParseKeyXml();
1937  //$this->template=$this->dom->saveXML();
1938  // print $this->template;exit;
1939  $this->ParseKey();
1940  $this->ParseText();
1941 
1942  $this->restoreUserFieldSet();
1943 
1944  $this->restoreProtectedValues();
1945 
1946  $this->ParseHtmlText();
1947 
1948  $this->template = \Dcp\Utils\htmlclean::cleanXMLUTF8($this->template);
1949  $this->dom = new DOMDocument();
1950  if ($this->dom->loadXML($this->template)) {
1951  $this->restoreSection();
1952  // not remove images because delete images defined in style.xml
1953  //$this->removeOrphanImages();
1954  $this->template = $this->dom->saveXML();
1955 
1956  $this->content_template = $this->template;
1957  } else {
1958  $outfile = uniqid(getTmpDir() . "/oooKo") . '.xml';
1959  file_put_contents($outfile, $this->template);
1960  $this->addError("LAY0004", $this->file);
1961  $this->exitError($outfile);
1962  }
1963  } else {
1964  $this->addError("LAY0001", $this->file);
1965  $this->exitError();
1966  }
1967  }
1968  /**
1969  * generate OOo document
1970  * get temporary file path of result
1971  * @throws Dcp\Layout\Exception
1972  * @return string odt file path
1973  */
1974  public function gen()
1975  {
1976  if (!$this->file) {
1977  $this->addError("LAY0001", $this->template);
1978  $this->exitError();
1979  }
1980  // if used in an app , set the app params
1981  if (is_object($this->action)) {
1982  $list = $this->action->parent->GetAllParam();
1983  foreach ($list as $k => $v) {
1984  $v = str_replace(array(
1985  '<BR>',
1986  '<br>',
1987  '<br/>',
1988  '<br />'
1989  ) , '<text:line-break/>', $v);
1990  $this->set($k, $v);
1991  }
1992  }
1993  // $this->rif=&$this->rkey;
1994  // $this->ParseIf($out);
1995  // Parse IMG: and LAY: tags
1996  $this->genContent();
1997  $this->genStyle();
1998  $this->genMeta();
1999  $this->updateManifest();
2000  $outfile = uniqid(getTmpDir() . "/odf") . '.odt';
2001  $this->content2odf($outfile);
2002 
2003  if (!empty($this->errors)) {
2004  //error_log(sprintf("Error {LAY0001}: corrupted temporary file is %s", $outfile));
2005  //throw new Dcp\Layout\Exception("LAY0001", $this->getErrors() , $outfile);
2006  $this->exitError($outfile);
2007  }
2008  //print_r2($this->content_template);
2009  return ($outfile);
2010  }
2011 }
2012 
Layout is a template generator.
← centre documentaire © anakeen