Read and replace contents in .docx (Word) file

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Document Templating in Laravel: Reading and Replacing Content in .docx Files

As developers working with document generation, a common requirement arises: how do we dynamically populate templates? You need to take a master file (like template.docx) and inject dynamic data—names, addresses, dates—into specific placeholders. This is a frequent task in business applications, but as you discovered with libraries like phpword, simple read/write operations often lead to frustrating formatting errors.

This post will dive deep into why standard document manipulation libraries struggle with this task and provide a robust, developer-centric solution for reading, modifying, and saving .docx files within a Laravel environment.

The Pitfalls of Simple Document Libraries

When working with formats like Microsoft Word's .docx, it is crucial to understand that these files are not simple text files; they are actually ZIP archives containing collections of XML files (specifically word/document.xml). To modify the content correctly, you must interact directly with this underlying XML structure.

Libraries designed primarily for creating new documents often handle the complex relationships between paragraphs, styles, and embedded objects automatically. However, when attempting to read an existing document and replace specific text nodes within these nested XML structures, libraries sometimes fail to maintain the integrity of the formatting, leading to corrupted output or messed-up spacing, just as you experienced with phpword.

The issue isn't just replacing text; it’s ensuring that the replacement respects the paragraph tags, line breaks, and style definitions present in the original document.

The Developer Solution: Direct XML Manipulation

For reliable content replacement in existing .docx files, the most robust approach is to bypass high-level document generation libraries for this specific task and perform direct manipulation of the underlying XML structure. This gives us full control over what we are reading and writing.

Since a .docx file is essentially a ZIP archive containing XML, we can read the content, modify the relevant XML nodes, and then repackage the files back into a valid .docx.

Step-by-Step Implementation Strategy

  1. Unzip the Document: Use PHP's built-in functionality or a library like ZipArchive to extract the contents of the .docx file.
  2. Locate the Target XML: Navigate to the word/document.xml file, which contains the main text content.
  3. Identify Placeholders: Use Regular Expressions (Regex) to find your placeholders (e.g., {fname}, {address}).
  4. Replace Content: Replace the matched placeholder strings with the actual data supplied by the user.
  5. Repackage and Save: Re-zip the modified XML files back into the .docx format.

This approach requires meticulous attention to file paths, but it guarantees that the document structure remains intact, which is paramount for professional application development—a principle central to building scalable systems on Laravel.

Code Example Concept (Conceptual PHP/Laravel Flow)

While a full, production-ready implementation involves complex XML handling, here is the conceptual flow demonstrating how this fits into a Laravel service layer:

php
<?php

namespace App\Services;

use Illuminate\Support\Facades\File;

class DocumentProcessor
{
    /**
     * Reads a DOCX, replaces placeholders, and saves the result.
     * @param string $templatePath Path to the template file.
     * @param array $data The dynamic data to insert.
     * @return string The path to the newly created document.
     */
    public function replaceContent(string $templatePath, array $data): string
    {
        if (!File::exists($templatePath)) {
            throw new \Exception("Template file not found.");
        }

        // 1. Read and Unzip the DOCX (Requires ZipArchive or similar)
        $zip = new \ZipArchive();
        $zip->open($templatePath);
        $files = $zip->extractTo(sys_get_temp_dir() . '/temp_docx');
        $zip->close();

        // 2. Process the core document.xml (This is where Regex replacement happens)
        $documentXmlPath = sys_get_temp_dir() . '/temp_docx/word/document.xml';
        $content = file_get_contents($documentXmlPath);
        
        // Example: Simple placeholder replacement using regex
        foreach ($data as $key => $value) {
            $placeholder = "{" . $key . "}";
            $content = preg_replace("/{$placeholder}/", $value, $content);
        }

        // 3. Write the modified content back to the XML file
        file_put_contents($documentXmlPath, $content);

        // 4. Repackage (Requires creating a new ZIP file) - Omitted for brevity but essential in practice.
        // ... logic to zip files back up ...

        return 'path/to/newly_generated.docx';
    }
}

Conclusion

When tackling complex file format manipulation in PHP, especially with proprietary formats like .docx, relying solely on high-level wrappers can obscure the necessary low-level details. For precise tasks like reading and replacing content while preserving formatting, diving into the underlying structure—in this case, XML manipulation—provides the necessary control. By embracing this approach within a structured framework like Laravel, you ensure that your document generation process is not only functional but also robust, scalable, and maintainable. Always prioritize understanding how the data is stored before trying to manipulate it!