Phpword: Cannot update a docx containing an image

Created on 30 Nov 2017  路  7Comments  路  Source: PHPOffice/PHPWord

I need to generate a pretty large Word document, with lots of data from a database.

Instead of fetching all the data in one go, and risking a timeout, I fetch a set number of elements at a time, and process the document in a batch.

A very crude simplification would look like this:

$filepath = '/absolute/path/to/file.docx';

// Initial batch run:
$phpword = new \PhpOffice\PhpWord\PhpWord();
$phpword->getSettings()->setUpdateFields(true);
// Set some settings...
$section = $phpword->addSection();
// Add text, images, etc;
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

// Subsequent batch runs:
$phpword = \PhpOffice\PhpWord\IOFactory::load($filepath);
$phpword->getSettings()->setUpdateFields(true);
// Set some settings...
$section = $phpword->addSection();
// Add text, images, etc;
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

So far so good.

However (and I've been banging my head for hours now), if at one point I add an image, I can no longer update the document. It will throw an exception: _Could not close zip file_, and PHP throws the following warning: _ZipArchive::close(): Invalid or uninitialized Zip object_.

If I use PeclZip, it will not throw any error, but the file won't be readable.

Expected Behavior

I would expect a document to be loaded correctly, and then be save-able again. This is the case as long as no image is added.

Current Behavior

If the document contains an image, it can be opened, but not updated.

I tried copying the file prior to opening it, renaming it, to no avail. I checked file permissions, but it doesn't seem to matter. I updated the user:group of the webserver to make certain it wasn't that either: no success.

Failure Information

\PhpOffice\PhpWord\Exception\Exception thrown: _Could not close zip file_ (in \PhpOffice\PhpWord\Shared\ZipArchive::close())
PHP warning: _ZipArchive::close(): Invalid or uninitialized Zip object_

How to Reproduce

Running this code triggers the error (I'm on the latest dev commit):

$filepath = '/absolute/path/to/file.docx';
$image = '/absolute/path/to/image.png';

$phpword = new \PhpOffice\PhpWord\PhpWord();
$phpword->getSettings()->setUpdateFields(true);
$phpword->setDefaultFontName('Verdana');
$phpword->setDefaultFontSize(9);
$section = $phpword->addSection();
$section->addImage($image);
$section->addTextBreak();
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

sleep(5); // This is not needed, but just to make absolutely sure 

$phpword = \PhpOffice\PhpWord\IOFactory::load($filepath);
$phpword->getSettings()->setUpdateFields(true);
$phpword->setDefaultFontName('Verdana');
$phpword->setDefaultFontSize(9);
$section = $phpword->addSection();
$section->addText('Lorem ipsum');
$section->addTextBreak();
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

Context

  • PHP version: 5.6.31 and 7.1.12
  • PHPWord version: master-dev
Responded

Most helpful comment

Experiencing same problem after adding image.

I am adding image like this:
$section->addImage($path);

And when trying to do it second time it errors out:

Invalid image: zip://F:\WEB\xampp\htdocs\workflow\storage\/app/files/FILENAME.docx#word/media/section_image1.jpg

All 7 comments

I forgot to mention that the initial exception is this one:

\PhpOffice\PhpWord\Exception\InvalidImageException: _Invalid image: zip:///absolute/path/to/file.docx#word/media/section_image1.png_ (in \PhpOffice\PhpWord\Element\Image::checkImage())

I applied the following changes, which gets a step further, but still fails to close the document (Exception described above):

diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php
index f1f6bab..68c813e 100644
--- a/src/PhpWord/Element/Image.php
+++ b/src/PhpWord/Element/Image.php
@@ -454,7 +454,7 @@ class Image extends AbstractElement

         $zip = new ZipArchive();
         if ($zip->open($zipFilename) !== false) {
-            if ($zip->locateName($imageFilename)) {
+            if ($zip->locateName($imageFilename) !== false) {
                 $imageContent = $zip->getFromName($imageFilename);
                 if ($imageContent !== false) {
                     file_put_contents($tempFilename, $imageContent);

what if you add the sections inside a function block? (so that variables get undefined when the function ends)
I suspect you actually need unset() to undefine/destroy all lingering variables before they get reused.
(or you are on to a bug)

Actually, the error also happens in a batch, where a JS function requests a
page, which triggers the PHP code. So the request ends, and no variables
are kept.

It works fine with just text. It also works if the first few batch calls
only add text, then one call adds an image. The next call will then fail,
regardless if we add text or an image.

@wadmiraal could you give it a try with the dev-develop version, just to make sure this is still valid?

I just tried again with the latest dev-develop branch. Clean install in another folder, called composer install to get a fresh copy of all dependencies.

I then modified src/PhpWord/Element/Image.php again, as noted in my previous comment, as the image is at position 0, which is a "falsy" value, and breaks the loading of a Docx file.

I then created the following PHP file in the root of the PHPWord repo (test.php):

require 'vendor/autoload.php';

$filepath = 'file.docx';
$image = 'image.png';

$phpword = new \PhpOffice\PhpWord\PhpWord();
$phpword->getSettings()->setUpdateFields(true);
$phpword->setDefaultFontName('Verdana');
$phpword->setDefaultFontSize(9);
$section = $phpword->addSection();
$section->addImage($image);
$section->addTextBreak();
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

sleep(5); // This is not needed, but just to make absolutely sure

$phpword = \PhpOffice\PhpWord\IOFactory::load($filepath);
$phpword->getSettings()->setUpdateFields(true);
$phpword->setDefaultFontName('Verdana');
$phpword->setDefaultFontSize(9);
$section = $phpword->addSection();
$section->addText('Lorem ipsum');
$section->addTextBreak();
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpword, 'Word2007');
$writer->save($filepath);

_Note: Make sure file.docx doesn't exist before executing the file._

I then executed it like this: php test.php.

Stack trace:

PHP Warning:  ZipArchive::close(): Invalid or uninitialized Zip object in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php on line 163
PHP Stack trace:
PHP   1. {main}() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:0
PHP   2. PhpOffice\PhpWord\Writer\Word2007->save() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:28
PHP   3. PhpOffice\PhpWord\Writer\AbstractWriter->addFilesToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/Word2007.php:111
PHP   4. PhpOffice\PhpWord\Writer\AbstractWriter->addFileToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:362
PHP   5. PhpOffice\PhpWord\Shared\ZipArchive->close() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:391
PHP   6. ZipArchive->close() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php:163

Warning: ZipArchive::close(): Invalid or uninitialized Zip object in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php on line 163

Call Stack:
    0.0002     364584   1. {main}() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:0
    5.0326    3125784   2. PhpOffice\PhpWord\Writer\Word2007->save() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:28
    5.0329    3126936   3. PhpOffice\PhpWord\Writer\AbstractWriter->addFilesToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/Word2007.php:111
    5.0329    3126992   4. PhpOffice\PhpWord\Writer\AbstractWriter->addFileToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:362
    5.0330    3127360   5. PhpOffice\PhpWord\Shared\ZipArchive->close() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:391
    5.0330    3127360   6. ZipArchive->close() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php:163

PHP Fatal error:  Uncaught PhpOffice\PhpWord\Exception\Exception: Could not close zip file file.docx. in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php:164
Stack trace:
#0 /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php(391): PhpOffice\PhpWord\Shared\ZipArchive->close()
#1 /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php(362): PhpOffice\PhpWord\Writer\AbstractWriter->addFileToPackage(Object(PhpOffice\PhpWord\Shared\ZipArchive), 'file.docx#word/...', 'word/media/sect...')
#2 /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/Word2007.php(111): PhpOffice\PhpWord\Writer\AbstractWriter->addFilesToPackage(Object(PhpOffice\PhpWord\Shared\ZipArchive), Array)
#3 /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php(28): PhpOffice\PhpWord\Writer\W in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php on line 164

Fatal error: Uncaught PhpOffice\PhpWord\Exception\Exception: Could not close zip file file.docx. in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php on line 164

PhpOffice\PhpWord\Exception\Exception: Could not close zip file file.docx. in /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Shared/ZipArchive.php on line 164

Call Stack:
    0.0002     364584   1. {main}() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:0
    5.0326    3125784   2. PhpOffice\PhpWord\Writer\Word2007->save() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/test.php:28
    5.0329    3126936   3. PhpOffice\PhpWord\Writer\AbstractWriter->addFilesToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/Word2007.php:111
    5.0329    3126992   4. PhpOffice\PhpWord\Writer\AbstractWriter->addFileToPackage() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:362
    5.0330    3127360   5. PhpOffice\PhpWord\Shared\ZipArchive->close() /Users/wadmiraal/Documents/inovae/projects/wto/tprqa/sites/all/libraries/PHPWord/src/PhpWord/Writer/AbstractWriter.php:391

Experiencing same problem after adding image.

I am adding image like this:
$section->addImage($path);

And when trying to do it second time it errors out:

Invalid image: zip://F:\WEB\xampp\htdocs\workflow\storage\/app/files/FILENAME.docx#word/media/section_image1.jpg

I have the same problem any solution ? The file forget de previous images
Check the result:
Screenshot_20200522-184852_Stack Exchange

Was this page helpful?
0 / 5 - 0 ratings