oneadvent
oneadvent

Reputation: 529

PHPWord export giving Corrupt Word File

I used the example code from PHPWord's site: http://phpword.codeplex.com/documentation And when I try and open it with Word I get the error "The Office Open XML file test.docx cannot be opened because there are problems with the contents." and when I click "Details" It simply says "The file is corrupt and cannot be opened." It does let me repair it and open it, but that wouldn't be very user friendly... Here is the code I'm using:

// Create a new PHPWord Object
$PHPWord = new PHPWord();

// Every element you want to append to the word document is placed in a section. So you need a section:
$section = $PHPWord->createSection();

// After creating a section, you can append elements:
$section->addText('Hello world!');

// You can directly style your text by giving the addText function an array:
$section->addText('Hello world! I am formatted.', array('name'=>'Tahoma', 'size'=>16, 'bold'=>true));

// If you often need the same style again you can create a user defined style to the word document
// and give the addText function the name of the style>:
$PHPWord->addFontStyle('myOwnStyle', array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232'));
$section->addText('Hello world! I am formatted by a user defined style', 'myOwnStyle');

// You can also putthe appended element to local object an call functions like this:
$myTextElement = $section->addText('Hello World!');



header('Content-Type: application/vnd.ms-word');
header('Content-Disposition: attachment;filename="test.docx"');
header('Cache-Control: max-age=0');
// At least write the document to webspace:
$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
$objWriter->save('php://output');

As you can see I did use php://output as the save there. Any ideas on how to get rid of the corruption. I did open the zip and saw that at the end of document.xml it appears there is blank line. Maybe that is causing it?

Thanks!

Upvotes: 10

Views: 27940

Answers (9)

Rohit Ramani
Rohit Ramani

Reputation: 954

Above Answers are great.

But for me I applied all above solutions but still I was getting issue. Finally I got solution by debugging each line.

Here are my findings.

If you add Row $phpWord->addRow(); without any line content after that you will also get Corrupt Word File issue.

$phpWord = new \PhpOffice\PhpWord\PhpWord();
$phpWord->setDefaultParagraphStyle(array('space' => array('line' =>10)));
$section = $phpWord->addSection(['marginLeft' => 600, 'marginRight' => 600]);
$textrun = $section->addTextRun();
$table_shipment_Detail = $section->addTable(); 
$table_shipment_Detail->addRow();

if($consignee->iec_no != ""){
   $table_shipment_Detail->addCell(800)->addText("IEC:".$consignee->iec_no);
}
if($consignee->gst_no != ""){
   $table_shipment_Detail->addCell(800)->addText("GST:".$consignee->gst_no);
}
if($consignee->tax_id != ""){
   $table_shipment_Detail->addCell(1500)->addText("TAX ID:".$consignee->tax_id);
}    

If you see above example, I have use $table_shipment_Detail->addRow(); but $consignee->iec_no, $consignee->tax_id, $consignee->tax_id are blank so when doc created it throws Corrupt Word File issue.

so I had to replace above code with following snippet.

$phpWord = new \PhpOffice\PhpWord\PhpWord();
$phpWord->setDefaultParagraphStyle(array('space' => array('line' =>10)));
$section = $phpWord->addSection(['marginLeft' => 600, 'marginRight' => 600]);
$textrun = $section->addTextRun();
$table_shipment_Detail = $section->addTable(); 
if($consignee->iec_no != "" || $consignee->gst_no != "" || $consignee->tax_id != ""){
    $table_shipment_Detail->addRow();
}
    
if($consignee->iec_no != ""){
     $table_shipment_Detail->addCell(800)->addText("IEC:".$consignee->iec_no);
}
if($consignee->gst_no != ""){
     $table_shipment_Detail->addCell(800)->addText("GST:".$consignee->gst_no);
}
if($consignee->tax_id != ""){
     $table_shipment_Detail->addCell(1500)->addText("TAX ID:".$consignee->tax_id);
}

I hope this will help someone.

Upvotes: 2

Ray Mo
Ray Mo

Reputation: 34

I did try all the methods but got errors. This fixed it. I was using the .PHP file under the

<!DOCTYPE html>
<html>
<head>
</head>
...........
<body>
<?PHP CODE ?>
</body>
</html>
```
The HTML encoding here was giving problems, once I removed all HTML HEAD and BODY  and DOCTYPE TAGS and left pre PHP Code 
```
<?PHP  .... ?>
```
Worked like a charm !!!
Cheers

Upvotes: 0

ManojKiran
ManojKiran

Reputation: 6341

While using PHPWord TemplateProcessor I faced the same issue.

By enabling setOutputEscapingEnabled from PhpOffice\PhpWord\Settings fixes the issue for me.

PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);  
$templateProcessor->saveAs($filepath);

As reported by Māris Kiseļovs

But You had to call setOutputEscapingEnabled before replacing values in template document

Upvotes: 6

Dong Zen
Dong Zen

Reputation: 41

  1. Add setCompatibility() before createWriter()

    \PhpOffice\PhpWord\Settings::setCompatibility(false);
    
  2. Add exit; after the save()

    // XML Writer compatibility
    \PhpOffice\PhpWord\Settings::setCompatibility(false);
    
    // Saving the document as OOXML file...
    $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
    ob_clean();
    $objWriter->save('php://output');
    
    exit;
    

Upvotes: 4

Juan Bilardi
Juan Bilardi

Reputation: 11

This solution worked for me

    $phpWord = new \PhpOffice\PhpWord\PhpWord();

$section = $phpWord->addSection(
  array('paperSize' => 'Legal', 'marginLeft' => 2834.645669291, 'marginRight' => 1417.322834646, 'marginTop' => 2834.645669291, 'marginBottom' => 1417.322834646)
);
//$html = $_POST['description'];
$html = $_POST['description'];


\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false);

// Save file
// Saving the document as OOXML file...
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
//$objWriter->save('test.docx');


  $temp_file_uri = tempnam('', 'xyz');
  $objWriter->save($temp_file_uri);
 //download code
  header('Content-Description: File Transfer');
  header('Content-Type: application/octet-stream');
  header('Content-Disposition: attachment; filename=helloWorld.docx');
  header('Content-Transfer-Encoding: binary');
  header('Expires: 0');
  header('Content-Length: ' . filesize($temp_file_uri));
  readfile($temp_file_uri);
  unlink($temp_file_uri); // deletes the temporary file
  exit;

Upvotes: 0

Cryborg
Cryborg

Reputation: 301

I know this is an old question but I had the exact same problem and just found the easiest solution of all. The problem I had is that I'm using Symfony, and that when generating the file, I had to edit the file with Notepad++ to see that there were error messages after the content, saying that the controller needed a Response().

So I ended up putting exit; just after the ->save(), and it worked fine.

Upvotes: 13

Oliver Markovic
Oliver Markovic

Reputation: 171

Just add ob_clean(); before output it!

ob_clean();
$objWriter->save('php://output');

This will clean you'r output, and now you are safe to generate docx file :)

Upvotes: 17

Siva
Siva

Reputation: 25

     $h2d_file_uri = tempnam('', 'htd');
    //exit($h2d_file_uri);
    $objWriter = PHPWord_IOFactory::createWriter($php_Word, 'Word2007');
    $objWriter->save($h2d_file_uri);


    // Download the file:
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
            header('Content-Disposition:    attachment;filename=BMP_QuotationNo_'.$html[0['quoteno'].'.docx');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($h2d_file_uri));
    ob_clean();
    flush();
    $status = readfile($h2d_file_uri);
    unlink($h2d_file_uri);
    exit;

Upvotes: 0

Usman Shaukat
Usman Shaukat

Reputation: 1331

Any Text you add should not contain HTML characters. Convert all applicable characters to HTML entities for example if you have to add the following "Me & my Code" first do this:

$Text_to_Add = htmlentities("Me & my Code");
$section->addText($Text_to_Add);

Use the Builtin function to save the file. docx files are zip files (you can open them in winrar or winzip) so you should not use php://output

$objWriter->save('helloWorld.docx');    
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=helloWorld.docx");
header("Content-Type: application/docx");
header("Content-Transfer-Encoding: binary");

This way the file will be created and then downloaded by user.

Side Note: docx files are actually XML files. So any xml reserve character will corrupt the file. A workaround is to convert your text as following

function xmlEntities($str)
{
    $xml = array('&#34;','&#38;','&#38;','&#60;','&#62;','&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;','&#167;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#175;','&#176;','&#177;','&#178;','&#179;','&#180;','&#181;','&#182;','&#183;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;','&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;','&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;','&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;');
    $html = array('&quot;','&amp;','&amp;','&lt;','&gt;','&nbsp;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;','&uml;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&macr;','&deg;','&plusmn;','&sup2;','&sup3;','&acute;','&micro;','&para;','&middot;','&cedil;','&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&frac34;','&iquest;','&Agrave;','&Aacute;','&Acirc;','&Atilde;','&Auml;','&Aring;','&AElig;','&Ccedil;','&Egrave;','&Eacute;','&Ecirc;','&Euml;','&Igrave;','&Iacute;','&Icirc;','&Iuml;','&ETH;','&Ntilde;','&Ograve;','&Oacute;','&Ocirc;','&Otilde;','&Ouml;','&times;','&Oslash;','&Ugrave;','&Uacute;','&Ucirc;','&Uuml;','&Yacute;','&THORN;','&szlig;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&divide;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&yuml;');
    $str = str_replace($html,$xml,$str);
    $str = str_ireplace($html,$xml,$str);
    return $str;
}


$Text_to_Add = htmlentities("Me & my Code");
$Test_to_Add_XML_Cleaned = xmlEntities($Text_to_Add);
$section->addText($Test_to_Add_XML_Cleaned);

Upvotes: 17

Related Questions