Modification classe PHPODT

Petit nouveau ! | 2 Messages

18 oct. 2012, 12:08

Bonjour,
Je tente de modifier la librairie PHP ODT celle-ci à la base se sert d'un fichier de template ouvre le content.xml et remplace les balises et rezippe le tout et permet de générer à la volée 1 fichier
Là mon besoin est de pouvoir générer à partir du même template 1 fichier multipages partir du même template, je me suis dit facile je concatène les contenus xml et je rezippe ça et hop c'est bon... eh bien non je coince le fichier se génère avec le contenu de xdebug dedans me disant : "WARNING : ZipArchive::getFromName() [ziparchive.getfromname]: Invalid oruninitialized Zip object in ....... odf.php on line 279"
<?php

require 'Segment.php';

class OdfException extends Exception {
    
}

/**
 * Templating class for odt file
 * You need PHP 5.2 at least
 * You need Zip Extension
 * Encoding : ISO-8859-1
 * Last commit by $Author: obooklage $
 * Date - $Date: 2009-02-14 21:44:18 +0100 $
 * SVN Revision - $Rev: 14 $
 * Id : $Id: odf.php 14 2009-02-14 20:44:18Z obooklage $
 *
 * @copyright  GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
 * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
 * @version 1.3
 */
class Odf {

    const DELIMITER_LEFT = '{';
    const DELIMITER_RIGHT = '}';
    const PIXEL_TO_CM = 0.026458333;

    public $file;
    public $contentXml;
    private $tmpfile;
    private $images = array();
    private $vars = array();
    private $segments = array();
    private $filename;

    /**
     * Constructeur de classe
     *
     * @param string $filename nom du fichier odt
     * @throws OdfException
     */
    public function __construct($filename) {
        
        $this->filename = $filename;
        
        if (!class_exists('ZipArchive')) {
            throw new OdfException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension
			 is required');
        }
        $this->file = new ZipArchive();
        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())) . '.odt';
        copy($filename, $tmp);
        $this->tmpfile = $tmp;
    }
    
    public function get_filename(){
        return $this->filename;
    }
    public function get_file(){
        return $this->file;
    }

    /**
     * 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) {
        if (strpos($this->contentXml, self::DELIMITER_LEFT . $key . self::DELIMITER_RIGHT) === false) {
            throw new OdfException("var $key not found in the document");
        }
        $value = $encode ? utf8_encode(htmlspecialchars($value)) : utf8_encode($value);
        $this->vars[self::DELIMITER_LEFT . $key . self::DELIMITER_RIGHT] = $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
<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>
IMG;
        $this->images[$value] = $file;
        $this->setVars($key, $xml, false);
        return $this;
    }

    /**
     * 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 = '@<text:p[^>]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@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('<pre>' . print_r($this->vars, true) . '</pre>', 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 '<pre>' . print_r(implode(' ', array_keys($this->segments)), true) . '</pre>';
    }

    /**
     * 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>(.*)<text:p\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]);
        return $this->segments[$segment];
    }

    /**
     * Sauvegarde le fichier odt sur le disque
     * 
     * @param string $file nom du fichier désiré
     * @return void
     */
    public function saveToDisk($file = null) {
        if ($file !== null && is_string($file)) {
            $this->file->open($this->tmpfile, ZIPARCHIVE::CREATE);
            $this->_save();
            copy($this->tmpfile, $file);
        } else {
            $this->_save();
        }
    }

    /**
     * Sauvegarde interne
     *
     * @throws OdfException
     * @return void
     */
    public function _save() {
        $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->file->open($this->tmpfile, ZIPARCHIVE::CREATE);
        $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);
    }

}

/*
 * Classe de création d'un fichier multi pages
 */

class multi_odf {

    private $array_Odf; // on fournit un tableau d'objets Odf
    private $xml;
    private $tmpFile;
    private $File;

    function __construct($array_odf) {

        //On initialise le fichier de sortie
        if (!class_exists('ZipArchive')) {
            throw new OdfException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension
			 is required');
        }
        $this->File = new ZipArchive();

        $this->array_Odf = $array_odf;

        foreach ($array_odf as $key => $odf) {

            if ($this->File->open($odf->get_filename()) !== true) {
                throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
            }
            
            //var_dump($odf->get_file());

            if (($this->xml .= $odf->get_file()->getFromName('content.xml')) === false) {
                throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed");
            }
        }

        $tmp = tempnam(null, md5(uniqid())) . '.odt';
        copy($filename, $tmp);
        $this->tmpFile = $tmp;
    }

    public function _toStringAll() {
        foreach ($this->array_Odf as $key => $odf) {
            $this->xml .= $odf->__toString();
        }

        return $this->xml;
    }

    private function _saveAll() {

        if (!$this->File->addFromString('content.xml', $this->xml)) {
            throw new OdfException('Error during file export');
        }

        $this->File->close(); // seems to bug on windows CLI sometimes
    }

    public function exportMultiOdfAsAttachedFile($name = "") {
        $this->File->open($this->tmpFile, ZIPARCHIVE::CREATE);
        $this->_saveAll();

        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);
    }

}

?>
Je sèche parce que je fournis pourtant un tableau d'objet odf à cette classe... Merci d'avance du coup de main

Petit nouveau ! | 2 Messages

19 oct. 2012, 09:41

Bon, je viens de trouver tout seul et comme je pense que cela pourrais aider certains, voici la solution :
<?php
require 'Segment.php';
class OdfException extends Exception { }
class Odf {

    const DELIMITER_LEFT = '{';
    const DELIMITER_RIGHT = '}';
    const PIXEL_TO_CM = 0.026458333;

    public $file;
    public $contentXml;
    private $tmpfile;
    private $images = array();
    private $vars = array();
    private $segments = array();
    private $filename;

    /**
     * Constructeur de classe
     *
     * @param string $filename nom du fichier odt
     * @throws OdfException
     */
    public function __construct($filename) {
        
        $this->filename = $filename;
        
        if (!class_exists('ZipArchive')) {
            throw new OdfException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension
			 is required');
        }
        $this->file = new ZipArchive();
        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())) . '.odt';
        copy($filename, $tmp);
        $this->tmpfile = $tmp;
    }
    
    public function get_filename(){
        return $this->filename;
    }
    public function get_file(){
        return $this->file;
    }

    /**
     * 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) {
        if (strpos($this->contentXml, self::DELIMITER_LEFT . $key . self::DELIMITER_RIGHT) === false) {
            throw new OdfException("var $key not found in the document");
        }
        $value = $encode ? utf8_encode(htmlspecialchars($value)) : utf8_encode($value);
        $this->vars[self::DELIMITER_LEFT . $key . self::DELIMITER_RIGHT] = $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
<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>
IMG;
        $this->images[$value] = $file;
        $this->setVars($key, $xml, false);
        return $this;
    }

    /**
     * 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 = '@<text:p[^>]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@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('<pre>' . print_r($this->vars, true) . '</pre>', 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 '<pre>' . print_r(implode(' ', array_keys($this->segments)), true) . '</pre>';
    }

    /**
     * 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>(.*)<text:p\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]);
        return $this->segments[$segment];
    }

    /**
     * Sauvegarde le fichier odt sur le disque
     * 
     * @param string $file nom du fichier désiré
     * @return void
     */
    public function saveToDisk($file = null) {
        if ($file !== null && is_string($file)) {
            $this->file->open($this->tmpfile, ZIPARCHIVE::CREATE);
            $this->_save();
            copy($this->tmpfile, $file);
        } else {
            $this->_save();
        }
    }

    /**
     * Sauvegarde interne
     *
     * @throws OdfException
     * @return void
     */
    public function _save() {
        $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->file->open($this->tmpfile, ZIPARCHIVE::CREATE);
        $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);
    }

}

/*
 * Classe de création d'un fichier multi pages
 */

class multi_odf {

    private $array_Odf; // on fournit un tableau d'objets Odf
    public $xml;
    private $tmpFile;
    private $File;

    function __construct($array_odf, $filename) {

        $this->File = new ZipArchive();

        if ($this->File->open($filename) !== true) {
            throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
        }

        //On initialise le fichier de sortie
        if (!class_exists('ZipArchive')) {
            throw new OdfException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension
			 is required');
        }


        $this->array_Odf = $array_odf;

        foreach ($array_odf as $key => $odf) {

            if ($this->File->open($odf->get_filename()) !== true) {
                throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
            }

            // On filtre les balises de début et fin de document
            // pour les injecter à la dernière itération
            if ($key == (sizeof($array_odf) - 1)) {
                
                // On insère le style pour le saut de page
                $needle = '</office:automatic-styles>';
                $replace = '<style:style style:name="saut1" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:break-before="page"/></style:style></office:automatic-styles>';
                str_replace($needle,$replace,$this->xml);
                
                
                $last_pos_office = strrpos($odf->contentXml, '</office:text>');
                $end_last_office = substr($odf->contentXml, $last_pos_office);
                
                $this->xml .= str_replace($end_last_office, $str_2_inject.$end_last_office, $odf->contentXml);

                //echo '<br />XML '.$key.': <br />'.$this->xml;//test
            } else {
                $reg_filter1 = '/<office:text>(.*?)<\/office:text>/';
                preg_match($reg_filter1, $odf->contentXml, $matches);
                $matches[0] = str_replace('<office:text>', '', $matches[0]);
                $str_2_inject .= str_replace('</office:text>', '<text:p text:style-name="saut1"/>', $matches[0]);
                 
            }
        }


        //echo 'size : '.sizeof($array_odf).'<br />';
        //echo 'XML : <br />'.$this->xml;
        //print_r($this->xml);
        //die();

        $tmp = tempnam(null, md5(uniqid())) . '.odt';
        copy($filename, $tmp);
        $this->tmpFile = $tmp;
    }

    public function _toStringAll() {
        foreach ($this->array_Odf as $key => $odf) {
            $this->xml .= $odf->__toString();
        }

        return $this->xml;
    }

    private function _saveAll() {

        if (!$this->File->addFromString('content.xml', $this->xml)) {
            throw new OdfException('Error during file export');
        }

        $this->File->close(); // seems to bug on windows CLI sometimes
    }

    public function exportMultiOdfAsAttachedFile($name = "") {
        $this->File->open($this->tmpFile, ZIPARCHIVE::CREATE);
        $this->_saveAll();

        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);
    }

}

?>
J'aurais préférré faire un simplexml_load_string pour pouvoir manipuler le DOM plus facilement mais hélas il n'y a pas moyen pour une raison que j'ignore, je suis obligé donc de faire un vieux str_replace pour arriver à mes fins si vous voyez une solution plus élégante et qui fonctionne bien pour manipuler le content.xml faites moi signe.