PHP

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

2013年11月25日

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
-, ,