かえでBlog

色々なことを徒然と……

【PHPWord】テンプレートを繰り返しで使用する方法

      2016/05/14

PHPで帳票出力する際、PDF出力ではなくて、WORD出力できるようにしてほしいという依頼がきたので、PHPWordというライブラリを使うことにしました。

PHPWordはテンプレートを呼び出して差し替えたい文字を修正すればいいのですが、1枚のテンプレートで複数枚のwordを抽出する方法がわかりませんでした。

そこで、調べてみるとTemplate.phpにAddPage関数+αを加えて使用すれば可能ということがわかりました。

52行目付近


    /**
     * Document XML
     *
     * @var string
     */
    private $_documentXML;

	//以下を追加
    private $_documentXMLSEQ;

    private $_documentXMLFINAL;

    private $_documentXMLREM;
    //追加ここまで

74行目付近

    /**
     * Create a new Template Object
     *
     * @param string $strFilename
     */
    public function __construct($strFilename) {
        $path = dirname($strFilename);
        $this->_tempFileName = $path.DIRECTORY_SEPARATOR.time().'.docx';

        copy($strFilename, $this->_tempFileName); // Copy the source File to the temp File

        $this->_objZip = new ZipArchive();
        $this->_objZip->open($this->_tempFileName);

        //Get xml
        $this->_documentXML = $this->_objZip->getFromName('word/document.xml');
		
        //追加ここから
        preg_match_all('/\$\{.+?\}/', $this->_documentXML, $matches, PREG_SET_ORDER);
        foreach ($matches as $val) {
            $oldval = $val[0];
            $newval = preg_replace('/\<.+?\>/', '', $val[0]);
            $newval = str_replace(' ', '', $newval );
            $this->_documentXML = str_replace($oldval, $newval, $this->_documentXML);
        }
        //Get code between body tag
        $this->_documentXMLSEQ = $this->getTextBetweenTags($this->_documentXML, 'w:body');

        //Get code outside tag and place string to replace later
        $count = null;
        $this->_documentXMLREM = preg_replace('/<w:body>(.*?)<\/w:body>/i', '[xmlremain]', $this->_documentXML, -1, $count);

        //Set code as string to replace
        $this->_documentXML = $this->_documentXMLSEQ;
        //追加ここまで
        
        }
        
        //追加ここから
        public    function getTextBetweenTags($string, $tagname) {
        $pattern = "/<$tagname>(.*?)<\/$tagname>/";
        preg_match($pattern, $string, $matches);

        return $matches[1];
     	}
        //追加ここまで

好きな箇所に挿入

    /**
     * Adds new page in the document
     */
    public function addPage() {
        $this->_documentXMLFINAL .=    $this->_documentXML;
        $this->_documentXML = $this->_documentXMLSEQ;
    }

95行目付近

    /**
     * Saves Template
     * @param string $strFilename
     */
    public function save($strFilename) {
        if(file_exists($strFilename)) {
            unlink($strFilename);
        }
    //追加ここから
        $this->_documentXMLFINAL .=    $this->_documentXML;
        $this->_documentXML = str_replace('[xmlremain]', '<w:body>'.$this->_documentXMLFINAL.'</w:body>', $this->_documentXMLREM);
    //追加ここまで
        $this->_objZip->addFromString('word/document.xml', $this->_documentXML);

        // Close zip file
        if($this->_objZip->close() === false) {
            throw new Exception('Could not close zip file.');
        }

        rename($this->_tempFileName, $strFilename);
    }

}

上記の修正でdocxを作成するとエラーが発生する場合があります。

SnapCrab_Microsoft Word_2013-11-25_16-6-59_No-00

原因を調べてみるとどうやら図形を使うとidの変更ができずid重複になりエラーになってしまうようです。

図形を使わないテンプレートにすると問題なかったので、できるだけ図形を使わない方向で対処しました。

この場合だと複数テンプレートで1つのwordを作成できないので、時間があれば複数テンプレ―トでも出力可能にしたいな……。

 

参考

 

 - PHP , ,