phplaravelphpwordphpoffice

PhpWord doesn't replace text with TemplateProcessor


I encountered the same issue as @pindol in here.

I followed some steps provider by users in the page issue. So i tested functions in TemplateProcessor to see the outputs, and finally, the hole $TemplateProcessor with var_dump :

object(PhpOffice\PhpWord\TemplateProcessor)#1259 (9) { ["zipClass":protected]=> object(PhpOffice\PhpWord\Shared\ZipArchive)#1008 (5) { ["numFiles"]=> int(11) ["filename"]=> string(18) "/tmp/PhpWord5qX68E" ["tempDir":"PhpOffice\PhpWord\Shared\ZipArchive":private]=> string(4) "/tmp" ["zip":"PhpOffice\PhpWord\Shared\ZipArchive":private]=> object(PclZip)#1046 (5) { ["zipname"]=> string(18) "/tmp/PhpWord5qX68E" ["zip_fd"]=> int(0) ["error_code"]=> int(0) ["error_string"]=> string(0) "" ["magic_quotes_status"]=> int(-1) } ["usePclzip":"PhpOffice\PhpWord\Shared\ZipArchive":private]=> bool(true) } ["tempDocumentFilename":protected]=> string(18) "/tmp/PhpWord5qX68E" ["tempDocumentMainPart":protected]=> string(2690) " Test : the test is perfect" ["tempDocumentSettingsPart":protected]=> string(2842) " " ["tempDocumentHeaders":protected]=> array(0) { } ["tempDocumentFooters":protected]=> array(0) { } ["tempDocumentRelations":protected]=> array(1) { ["word/document.xml"]=> string(817) " " } ["tempDocumentContentTypes":protected]=> string(1312) " " ["tempDocumentNewImages":protected]=> array(0) { } } 

As we can see in ["tempDocumentMainPart":protected], the variable was replaced successfully with this function :

    $templateProcessor = new TemplateProcessor('results/test.docx');
    $templateProcessor->setValue('test', 'the test is perfect'); 
    var_dump($templateProcessor);
    exit();
    $templateProcessor->saveAs('results/results.docx');
    return response()->download('results/results.docx');

But when i tried to saveAs or download the file, the variable doesn't change in the downloaded file. It's the same like the template provided and i got a error message when i try to open it (After download):

Word found unreadable content in results.docx. Do you want to recover the contents of this document? If the source for this document is reliable, click Yes.

The function save and saveAs in the phpword :

    /**
 * Saves the result document.
 *
 * @throws \PhpOffice\PhpWord\Exception\Exception
 *
 * @return string
 */
public function save()
{
    foreach ($this->tempDocumentHeaders as $index => $xml) {
        $this->savePartWithRels($this->getHeaderName($index), $xml);
    }

    $this->savePartWithRels($this->getMainPartName(), $this->tempDocumentMainPart);

    foreach ($this->tempDocumentFooters as $index => $xml) {
        $this->savePartWithRels($this->getFooterName($index), $xml);
    }

    $this->zipClass->addFromString($this->getDocumentContentTypesName(), $this->tempDocumentContentTypes);

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

    return $this->tempDocumentFilename;
}

/**
 * @param string $fileName
 * @param string $xml
 */
protected function savePartWithRels($fileName, $xml)
{
    $this->zipClass->addFromString($fileName, $xml);
    if (isset($this->tempDocumentRelations[$fileName])) {
        $relsFileName = $this->getRelationsName($fileName);
        $this->zipClass->addFromString($relsFileName, $this->tempDocumentRelations[$fileName]);
    }
}

/**
 * Saves the result document to the user defined file.
 *
 * @since 0.8.0
 *
 * @param string $fileName
 */
public function saveAs($fileName)
{
    $tempFileName = $this->save();

    if (file_exists($fileName)) {
        unlink($fileName);
    }

    /*
     * Note: we do not use `rename` function here, because it loses file ownership data on Windows platform.
     * As a result, user cannot open the file directly getting "Access denied" message.
     *
     * @see https://github.com/PHPOffice/PHPWord/issues/532
     */
    copy($tempFileName, $fileName);
    unlink($tempFileName);
}

I tested this in the PhpWord 0.16.0 and 0.17.0 and i use this with laravel (i don't think that the issue is with laravel). Php version :

PHP 7.4.7 (cli) (built: Jun 12 2020 07:48:26) ( NTS )

I'm using PCLZIP instead of zipArchive because he generate a memory issue. Thanks in advance


Solution

  • I ran into the same problem and managed to fix it !

    I work on MacOS using the shipped version of Apache2, I don't know if you are still having this issue and in the same environnement as me, but I'm posting anyway in case someone else encounters the same issue.

    Steps :

    1. Download php@8.0

    To download php@8.0, I ran the following commands (source):

    brew tap shivammathur/php
    brew install shivammathur/php/php@8.0
    brew link --overwrite --force php@8.0
    

    Not php@8.1, this version (as of february 2022) causes DEPRECATED messages to show up GitHub Issue

    2. Update Apache2 configuration

    And then I updated my /etc/apache2/httpd.conf file according to the brew installer message

    (always backup your config files before editing them!)

    To enable PHP in Apache add the following to httpd.conf and restart Apache:
        LoadModule php_module /usr/local/opt/php/lib/httpd/modules/libphp.so
    
        <FilesMatch \.php$>
            SetHandler application/x-httpd-php
        </FilesMatch>
    
    Finally, check DirectoryIndex includes index.php
        DirectoryIndex index.php index.html
    

    I changed the LoadModule path to /usr/local/opt/php@8.0/lib/httpd/modules/libphp.so as I had multiple versions of php downloaded

    Then restarted Apache2 using :

    sudo apachectl restart
    

    3. Use ZipArchive

    Remove Settings::setZipClass(Settings::PCLZIP); and use ZipArchive.

    I can't assure that your problems using ZipArchive will disappear using php@8.0 as you seem to be having an other problem than I was, which was that ZipArchive was simply not found on my system.

    Conclusion :

    My guess is that the issue comes with Settings::setZipClass(Settings::PCLZIP) unable to create normal OOXML (but only when using TemplateProcessor for some reason ? Because it worked perfectly when creating a new document with new PhpWord())