'PclZipProxy', 'DELIMITER_LEFT' => '[', 'DELIMITER_RIGHT' => ']' ); protected $file; protected $contentXml; protected $tmpfile; protected $images = array(); protected $vars = array(); protected $segments = array(); const PIXEL_TO_CM = 0.026458333; /** * Constructeur de classe * * @param string $filename nom du fichier odt * @throws OdfException */ public function __construct($filename, $config = array()) { if (! is_array($config)) { throw new OdfException('Configuration data must be passed as array'); } foreach ($config as $configKey => $configValue) { if (array_key_exists($configKey, $this->config)) { $this->config[$configKey] = $configValue; } } if (! class_exists($this->config['ZIP_PROXY'])) { throw new OdfException($this->config['ZIP_PROXY'] . ' class not found - check your php settings'); } $zipHandler = $this->config['ZIP_PROXY']; $this->file = new $zipHandler(); if ($this->file->open($filename) !== true) { throw new OdfException("Error while Opening the file '$filename' - Check your odt file"); } if (($this->contentXml = $this->file->getFromName('content.xml')) === false) { throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed"); } $this->file->close(); $tmp = tempnam(null, md5(uniqid())); copy($filename, $tmp); $this->tmpfile = $tmp; $this->_moveRowSegments(); } /** * Affecte une variable de template * * @param string $key nom de la variable dans le template * @param string $value valeur de remplacement * @param bool $encode si true, les caractères spéciaux XML seront encodés * @throws OdfException * @return odf */ public function setVars($key, $value, $encode = true, $charset = 'ISO-8859') { if (strpos($this->contentXml, $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']) === false) { //throw new OdfException("var $key not found in the document"); } $value = $encode ? htmlspecialchars($value) : $value; $value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value; $this->vars[$this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']] = str_replace("\n", "", $value); return $this; } /** * Affecte une variable de template en tant qu'image * * @param string $key nom de la variable dans le template * @param string $value chemin vers une image * @throws OdfException * @return odf */ public function setImage($key, $value) { $filename = strtok(strrchr($value, '/'), '/.'); $file = substr(strrchr($value, '/'), 1); $size = @getimagesize($value); if ($size === false) { throw new OdfException("Invalid image"); } list ($width, $height) = $size; $width *= self::PIXEL_TO_CM; $height *= self::PIXEL_TO_CM; $xml = << IMG; $this->images[$value] = $file; $this->setVars($key, $xml, false); return $this; } /** * Déplace les balises des Segments pour les lignes de tableaux * Appelée automatiquement dans le constructeur * * @return void */ private function _moveRowSegments() { // Search all possible rows in the document $reg1 = "#]*>(.*)#smU"; preg_match_all($reg1, $this->contentXml, $matches); for ($i = 0, $size = count($matches[0]); $i < $size; $i++) { // Check if the current row contains a segment row.* $reg2 = '#\[!--\sBEGIN\s(row.[\S]*)\s--\](.*)\[!--\sEND\s\\1\s--\]#sm'; if (preg_match($reg2, $matches[0][$i], $matches2)) { $balise = str_replace('row.', '', $matches2[1]); // Move segment tags around the row $replace = array( '[!-- BEGIN ' . $matches2[1] . ' --]' => '', '[!-- END ' . $matches2[1] . ' --]' => '', ' '[!-- BEGIN ' . $balise . ' --]' => '[!-- END ' . $balise . ' --]' ); $replacedXML = str_replace(array_keys($replace), array_values($replace), $matches[0][$i]); $this->contentXml = str_replace($matches[0][$i], $replacedXML, $this->contentXml); } } } /** * Fusionne les variables de template * Appelée automatiquement lors d'une sauvegarde * * @return void */ private function _parse() { $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml); } /** * Rajoute le segment fusionné au document * * @param Segment $segment * @throws OdfException * @return odf */ public function mergeSegment(Segment $segment) { if (! array_key_exists($segment->getName(), $this->segments)) { throw new OdfException($segment->getName() . 'cannot be parsed, has it been set yet ?'); } $string = $segment->getName(); // $reg = '@]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@smU'; $reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU'; $this->contentXml = preg_replace($reg, $segment->getXmlParsed(), $this->contentXml); return $this; } /** * Affiche toutes les variables de templates actuelles * * @return string */ public function printVars() { return print_r('
' . print_r($this->vars, true) . '
', true); } /** * Affiche le fichier de contenu xml du document odt * tel qu'il est à cet instant * * @return string */ public function __toString() { return $this->contentXml; } /** * Affiche les segments de boucles déclarés avec setSegment() * * @return string */ public function printDeclaredSegments() { return '
' . print_r(implode(' ', array_keys($this->segments)), true) . '
'; } /** * Déclare un segment pour une utilisation en boucle * * @param string $segment * @throws OdfException * @return Segment */ public function setSegment($segment) { if (array_key_exists($segment, $this->segments)) { return $this->segments[$segment]; } // $reg = "#\[!--\sBEGIN\s$segment\s--\]<\/text:p>(.*)\[!--\sEND\s$segment\s--\]#sm"; $reg = "#\[!--\sBEGIN\s$segment\s--\](.*)\[!--\sEND\s$segment\s--\]#sm"; if (preg_match($reg, html_entity_decode($this->contentXml), $m) == 0) { throw new OdfException("'$segment' segment not found in the document"); } $this->segments[$segment] = new Segment($segment, $m[1], $this); return $this->segments[$segment]; } /** * Sauvegarde le fichier odt sur le disque * * @param string $file nom du fichier désiré * @throws OdfException * @return void */ public function saveToDisk($file = null) { if ($file !== null && is_string($file)) { if (file_exists($file) && !(is_file($file) && is_writable($file))) { throw new OdfException('Permission denied : can\'t create ' . $file); } $this->_save(); copy($this->tmpfile, $file); } else { $this->_save(); } } /** * Sauvegarde interne * * @throws OdfException * @return void */ private function _save() { $this->file->open($this->tmpfile); $this->_parse(); if (! $this->file->addFromString('content.xml', $this->contentXml)) { throw new OdfException('Error during file export'); } foreach ($this->images as $imageKey => $imageValue) { $this->file->addFile($imageKey, 'Pictures/' . $imageValue); } $this->file->close(); // seems to bug on windows CLI sometimes } /** * Exporte le fichier en fichier attaché via HTTP * * @param string $name (optionnal) * @throws OdfException * @return void */ public function exportAsAttachedFile($name="") { $this->_save(); if (headers_sent($filename, $linenum)) { throw new OdfException("headers already sent ($filename at $linenum)"); } if( $name == "" ) { $name = md5(uniqid()) . ".odt"; } header('Content-type: application/vnd.oasis.opendocument.text'); header('Content-Disposition: attachment; filename="'.$name.'"'); readfile($this->tmpfile); } /** * retourne une variable de configuration * * @return string la variable de configuration demandée */ public function getConfig($configKey) { if (array_key_exists($configKey, $this->config)) { return $this->config[$configKey]; } return false; } /** * retourne le fichier temporaire de travail * * @return string le chemin vers le fichier temporaire de travail */ public function getTmpfile() { return $this->tmpfile; } /** * Supprime le fichier temporaire à la destruction de l'objet */ public function __destruct() { if (file_exists($this->tmpfile)) { unlink($this->tmpfile); } } } ?>