📜 ⬆️ ⬇️

Fair DOCX generation in PHP. Part 1

image Hello, dear habrasoobschestvu! Once there was an interesting material on the generation of doc-files using PHP. Unfortunately, I didn’t find anything else on this topic. At that time, I developed my own solution.
It was to generate .docx files. The arguments were as follows:


Details under the cut.

File structure


imageimage Take your any .docx file and rename it to .zip and then open. And you will see the structure of the docx file. Yes Yes! This is a regular zip archive. I will briefly say that the most interesting thing for us lies in the word folder. Here, in the root are the general settings of the document.
The most interesting thing for us in the word folder is the document.xml file, which is a file with the contents of Office Open XML. That it contains the contents of the document itself. More information about this format can be found on the English Wikipedia . The _rels folder contains the document.xml.rels file. It will be useful to us in the future to describe the links of attached files within the document. The media folder may still exist if there are images in your document. The names of the remaining files seem to speak for themselves.
')

Learning to generate .docx


So, as we have already decided, .docx is just a regular zip archive, so the solution suggests itself: the document generator class must be an heir of the ZipArchive class, which is available out of the box. And the rest is a matter of technique. Below is a class for creating an empty .docx file (do not forget to enable zlib and use UTF-8 encoding).
class Word extends ZipArchive{ //      private $files; //    public $path; public function __construct($filename, $template_path = '/template/' ){ //    $this->path = dirname(__FILE__) . $template_path; //     ,   . if ($this->open($filename, ZIPARCHIVE::CREATE) !== TRUE) { die("Unable to open <$filename>\n"); } //   $this->files = array( "word/_rels/document.xml.rels", "word/theme/theme1.xml", "word/fontTable.xml", "word/settings.xml", "word/styles.xml", "word/document.xml", "word/stylesWithEffects.xml", "word/webSettings.xml", "_rels/.rels", "docProps/app.xml", "docProps/core.xml", "[Content_Types].xml" ); //      foreach( $this->files as $f ) $this->addFile($this->path . $f , $f ); } //   public function create(){ $this->close(); } } $w = new Word( "Example.docx" ); $w->create(); 

The file Example.docx should appear near the script. At the same time, do not forget to create the file structure itself. To get it, we use the notorious MS Office and Winrar. After assembly, try to open in through MS Office. In case of minor errors in the XML, the Word will warn you that the document contains errors, but will also suggest correcting them. If the document is collected completely wrong, the Word will only curse and refuse to open.

Paste the text


To obtain the required XML text, I used the same lamer approach: I typed text in a Word, extracted the insides, and studied. Here is what XML I got for the usual paragraph:
 <w:pw:rsidR="00BB20FC" w:rsidRPr="00357A74" w:rsidRDefault="00357A74" w:rsidP="00BB20FC"> <w:pPr> <w:jc w:val="left"/> <w:rPr> <w:sz w:val="28"/> <w:lang w:val="en-US"/> </w:rPr> </w:pPr> <w:rw:rsidRPr="00357A74"> <w:rPr> <w:sz w:val="28"/> <w:lang w:val="en-US"/> </w:rPr> <w:t>{TEXT}</w:t> </w:r> </w:p> 

It is easy to understand what needs to be changed to get the desired alignment and text size. We insert our text into the w: t tag, but without line breaks!
We introduce the assign method into our class, and the generator becomes like this:
 class Word extends ZipArchive{ //      private $files; //    public $path; //   protected $content; public function __construct($filename, $template_path = '/template/' ){ //    $this->path = dirname(__FILE__) . $template_path; //     ,   . if ($this->open($filename, ZIPARCHIVE::CREATE) !== TRUE) { die("Unable to open <$filename>\n"); } //   $this->files = array( "word/_rels/document.xml.rels", "word/theme/theme1.xml", "word/fontTable.xml", "word/settings.xml", "word/styles.xml", "word/stylesWithEffects.xml", "word/webSettings.xml", "_rels/.rels", "docProps/app.xml", "docProps/core.xml", "[Content_Types].xml" ); //      foreach( $this->files as $f ) $this->addFile($this->path . $f , $f ); } //   public function assign( $text = '' ){ //    $p = file_get_contents( $this->path . 'p.xml' ); //       $text_array = explode( "\n", $text ); foreach( $text_array as $str ) $this->content .= str_replace( '{TEXT}', $str, $p ); } //   public function create(){ //   $this->addFromString("word/document.xml", str_replace( '{CONTENT}', $this->content, file_get_contents( $this->path . "word/document.xml" ) ) ); $this->close(); } } $w = new Word( ".docx" ); $w->assign(' .   .'); $w->create(); 

That's basically it. Next time we learn to embed images.
Simple, isn't it? All code with an example .
UPD. Made a code highlighting.
UPD 2. Read the sequel .

Source: https://habr.com/ru/post/138666/


All Articles