PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/odtphp-1.0.1/library/odf.php

https://gitlab.com/braydon/legal-documents
PHP | 311 lines | 189 code | 5 blank | 117 comment | 27 complexity | 16fe3808ef55f67e89608fb34273561c MD5 | raw file
  1. <?php
  2. require 'zip/PclZipProxy.php';
  3. require 'zip/PhpZipProxy.php';
  4. require 'Segment.php';
  5. class OdfException extends Exception
  6. {}
  7. /**
  8. * Templating class for odt file
  9. * You need PHP 5.2 at least
  10. * You need Zip Extension or PclZip library
  11. * Encoding : ISO-8859-1
  12. * Last commit by $Author: neveldo $
  13. * Date - $Date: 2009-06-17 11:11:57 +0200 (mer., 17 juin 2009) $
  14. * SVN Revision - $Rev: 42 $
  15. * Id : $Id: odf.php 42 2009-06-17 09:11:57Z neveldo $
  16. *
  17. * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
  18. * @license http://www.gnu.org/copyleft/gpl.html GPL License
  19. * @version 1.3
  20. */
  21. class Odf
  22. {
  23. protected $config = array(
  24. 'ZIP_PROXY' => 'PclZipProxy',
  25. 'DELIMITER_LEFT' => '{',
  26. 'DELIMITER_RIGHT' => '}',
  27. 'PATH_TO_TMP' => null
  28. );
  29. protected $file;
  30. protected $contentXml;
  31. protected $tmpfile;
  32. protected $images = array();
  33. protected $vars = array();
  34. protected $segments = array();
  35. const PIXEL_TO_CM = 0.026458333;
  36. /**
  37. * Class constructor
  38. *
  39. * @param string $filename the name of the odt file
  40. * @throws OdfException
  41. */
  42. public function __construct($filename, $config = array())
  43. {
  44. if (! is_array($config)) {
  45. throw new OdfException('Configuration data must be provided as array');
  46. }
  47. foreach ($config as $configKey => $configValue) {
  48. if (array_key_exists($configKey, $this->config)) {
  49. $this->config[$configKey] = $configValue;
  50. }
  51. }
  52. if (! class_exists($this->config['ZIP_PROXY'])) {
  53. throw new OdfException($this->config['ZIP_PROXY'] . ' class not found - check your php settings');
  54. }
  55. $zipHandler = $this->config['ZIP_PROXY'];
  56. $this->file = new $zipHandler();
  57. if ($this->file->open($filename) !== true) {
  58. throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
  59. }
  60. if (($this->contentXml = $this->file->getFromName('content.xml')) === false) {
  61. throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed");
  62. }
  63. $this->file->close();
  64. $tmp = tempnam($this->config['PATH_TO_TMP'], md5(uniqid()));
  65. copy($filename, $tmp);
  66. $this->tmpfile = $tmp;
  67. $this->_moveRowSegments();
  68. }
  69. /**
  70. * Assing a template variable
  71. *
  72. * @param string $key name of the variable within the template
  73. * @param string $value replacement value
  74. * @param bool $encode if true, special XML characters are encoded
  75. * @throws OdfException
  76. * @return odf
  77. */
  78. public function setVars($key, $value, $encode = true, $charset = 'ISO-8859')
  79. {
  80. if (strpos($this->contentXml, $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']) === false) {
  81. throw new OdfException("var $key not found in the document");
  82. }
  83. $value = $encode ? htmlspecialchars($value) : $value;
  84. $value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value;
  85. $this->vars[$this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']] = str_replace("\n", "<text:line-break/>", $value);
  86. return $this;
  87. }
  88. /**
  89. * Assign a template variable as a picture
  90. *
  91. * @param string $key name of the variable within the template
  92. * @param string $value path to the picture
  93. * @throws OdfException
  94. * @return odf
  95. */
  96. public function setImage($key, $value)
  97. {
  98. $filename = strtok(strrchr($value, '/'), '/.');
  99. $file = substr(strrchr($value, '/'), 1);
  100. $size = @getimagesize($value);
  101. if ($size === false) {
  102. throw new OdfException("Invalid image");
  103. }
  104. list ($width, $height) = $size;
  105. $width *= self::PIXEL_TO_CM;
  106. $height *= self::PIXEL_TO_CM;
  107. $xml = <<<IMG
  108. <draw:frame draw:style-name="fr1" draw:name="$filename" text:anchor-type="char" svg:width="{$width}cm" svg:height="{$height}cm" draw:z-index="3"><draw:image xlink:href="Pictures/$file" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame>
  109. IMG;
  110. $this->images[$value] = $file;
  111. $this->setVars($key, $xml, false);
  112. return $this;
  113. }
  114. /**
  115. * Move segment tags for lines of tables
  116. * Called automatically within the constructor
  117. *
  118. * @return void
  119. */
  120. private function _moveRowSegments()
  121. {
  122. // Search all possible rows in the document
  123. $reg1 = "#<table:table-row[^>]*>(.*)</table:table-row>#smU";
  124. preg_match_all($reg1, $this->contentXml, $matches);
  125. for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
  126. // Check if the current row contains a segment row.*
  127. $reg2 = '#\[!--\sBEGIN\s(row.[\S]*)\s--\](.*)\[!--\sEND\s\\1\s--\]#sm';
  128. if (preg_match($reg2, $matches[0][$i], $matches2)) {
  129. $balise = str_replace('row.', '', $matches2[1]);
  130. // Move segment tags around the row
  131. $replace = array(
  132. '[!-- BEGIN ' . $matches2[1] . ' --]' => '',
  133. '[!-- END ' . $matches2[1] . ' --]' => '',
  134. '<table:table-row' => '[!-- BEGIN ' . $balise . ' --]<table:table-row',
  135. '</table:table-row>' => '</table:table-row>[!-- END ' . $balise . ' --]'
  136. );
  137. $replacedXML = str_replace(array_keys($replace), array_values($replace), $matches[0][$i]);
  138. $this->contentXml = str_replace($matches[0][$i], $replacedXML, $this->contentXml);
  139. }
  140. }
  141. }
  142. /**
  143. * Merge template variables
  144. * Called automatically for a save
  145. *
  146. * @return void
  147. */
  148. private function _parse()
  149. {
  150. $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml);
  151. }
  152. /**
  153. * Add the merged segment to the document
  154. *
  155. * @param Segment $segment
  156. * @throws OdfException
  157. * @return odf
  158. */
  159. public function mergeSegment(Segment $segment)
  160. {
  161. if (! array_key_exists($segment->getName(), $this->segments)) {
  162. throw new OdfException($segment->getName() . 'cannot be parsed, has it been set yet ?');
  163. }
  164. $string = $segment->getName();
  165. // $reg = '@<text:p[^>]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@smU';
  166. $reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU';
  167. $this->contentXml = preg_replace($reg, $segment->getXmlParsed(), $this->contentXml);
  168. return $this;
  169. }
  170. /**
  171. * Display all the current template variables
  172. *
  173. * @return string
  174. */
  175. public function printVars()
  176. {
  177. return print_r('<pre>' . print_r($this->vars, true) . '</pre>', true);
  178. }
  179. /**
  180. * Display the XML content of the file from odt document
  181. * as it is at the moment
  182. *
  183. * @return string
  184. */
  185. public function __toString()
  186. {
  187. return $this->contentXml;
  188. }
  189. /**
  190. * Display loop segments declared with setSegment()
  191. *
  192. * @return string
  193. */
  194. public function printDeclaredSegments()
  195. {
  196. return '<pre>' . print_r(implode(' ', array_keys($this->segments)), true) . '</pre>';
  197. }
  198. /**
  199. * Declare a segment in order to use it in a loop
  200. *
  201. * @param string $segment
  202. * @throws OdfException
  203. * @return Segment
  204. */
  205. public function setSegment($segment)
  206. {
  207. if (array_key_exists($segment, $this->segments)) {
  208. return $this->segments[$segment];
  209. }
  210. // $reg = "#\[!--\sBEGIN\s$segment\s--\]<\/text:p>(.*)<text:p\s.*>\[!--\sEND\s$segment\s--\]#sm";
  211. $reg = "#\[!--\sBEGIN\s$segment\s--\](.*)\[!--\sEND\s$segment\s--\]#sm";
  212. if (preg_match($reg, html_entity_decode($this->contentXml), $m) == 0) {
  213. throw new OdfException("'$segment' segment not found in the document");
  214. }
  215. $this->segments[$segment] = new Segment($segment, $m[1], $this);
  216. return $this->segments[$segment];
  217. }
  218. /**
  219. * Save the odt file on the disk
  220. *
  221. * @param string $file name of the desired file
  222. * @throws OdfException
  223. * @return void
  224. */
  225. public function saveToDisk($file = null)
  226. {
  227. if ($file !== null && is_string($file)) {
  228. if (file_exists($file) && !(is_file($file) && is_writable($file))) {
  229. throw new OdfException('Permission denied : can\'t create ' . $file);
  230. }
  231. $this->_save();
  232. copy($this->tmpfile, $file);
  233. } else {
  234. $this->_save();
  235. }
  236. }
  237. /**
  238. * Internal save
  239. *
  240. * @throws OdfException
  241. * @return void
  242. */
  243. private function _save()
  244. {
  245. $this->file->open($this->tmpfile);
  246. $this->_parse();
  247. if (! $this->file->addFromString('content.xml', $this->contentXml)) {
  248. throw new OdfException('Error during file export');
  249. }
  250. foreach ($this->images as $imageKey => $imageValue) {
  251. $this->file->addFile($imageKey, 'Pictures/' . $imageValue);
  252. }
  253. $this->file->close(); // seems to bug on windows CLI sometimes
  254. }
  255. /**
  256. * Export the file as attached file by HTTP
  257. *
  258. * @param string $name (optionnal)
  259. * @throws OdfException
  260. * @return void
  261. */
  262. public function exportAsAttachedFile($name="")
  263. {
  264. $this->_save();
  265. if (headers_sent($filename, $linenum)) {
  266. throw new OdfException("headers already sent ($filename at $linenum)");
  267. }
  268. if( $name == "" )
  269. {
  270. $name = md5(uniqid()) . ".odt";
  271. }
  272. header('Content-type: application/vnd.oasis.opendocument.text');
  273. header('Content-Disposition: attachment; filename="'.$name.'"');
  274. readfile($this->tmpfile);
  275. }
  276. /**
  277. * Returns a variable of configuration
  278. *
  279. * @return string The requested variable of configuration
  280. */
  281. public function getConfig($configKey)
  282. {
  283. if (array_key_exists($configKey, $this->config)) {
  284. return $this->config[$configKey];
  285. }
  286. return false;
  287. }
  288. /**
  289. * Returns the temporary working file
  290. *
  291. * @return string le chemin vers le fichier temporaire de travail
  292. */
  293. public function getTmpfile()
  294. {
  295. return $this->tmpfile;
  296. }
  297. /**
  298. * Delete the temporary file when the object is destroyed
  299. */
  300. public function __destruct() {
  301. if (file_exists($this->tmpfile)) {
  302. unlink($this->tmpfile);
  303. }
  304. }
  305. }
  306. ?>