Library / SDK
PHPOffice/PHPWord avatar
PHPOffice/PHPWord

PHPWord's optional dependencies decide which formats you can write

A pure PHP library for reading and writing word processing documents

7,588 stars2,732 forksPHPNOASSERTION

At a glance

What is it?
A pure PHP library for reading and writing office documents, licensed LGPL version 3 and installed with a single Composer line. The architecture is unusually legible: document properties, sections, then content, and every element you append has to live inside a section.
Who is it for?
PHPWord fits a PHP application that has to emit or ingest a real document rather than a rendered page, and that wants charts, footnotes, tables and templates without a conversion service. It does not fit someone who needs pixel-perfect layout matching, because the feature list is about document structure rather than visual fidelity.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • PHPOffice/PHPWord7,588 ★ · -3
Star history
Repository2026-09-222026-11-14
PHPOffice/PHPWord7.6k7.6k

-3 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Everything you append has to live inside a section

The getting started example is short, and one line in it is the rule the rest of the library depends on: any element you append to a document must reside inside a section.

The example creates a document object, adds an empty section to it, and then adds text to that section.

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

/* Note: any element you append to a document must reside inside of a Section. */

// Adding an empty Section to the document...
$section = $phpWord->addSection();

That constraint is not a limitation so much as the shape of the document model. Sections carry their own settings, and the feature list spells out what those are: orientation such as portrait or landscape, page size, and page numbering, plus a header and a footer per section.

So the section is where page layout lives, and every piece of content is added to one. A document with two different page orientations is two sections rather than one document with a setting.

Four extensions are optional and each maps to a format

The requirements list is short and precise, with three items required and five marked optional.

Required are PHP 7.1 or newer, the XML parser extension, and the Laminas Escaper component, which is a separate library rather than a PHP extension.

Then the optional ones, each with the reason it exists. The Zip extension is used to write OOXML and ODF, since both are zip containers. The XMLWriter extension is also used to write those two formats. The GD extension is used to add images. The XSL extension applies an XSL stylesheet to a template. And the dompdf library is used to write PDF.

Read as a group, they tell you the cost of each format. OOXML and ODF need two extensions between them, images need another, PDF needs an entire separate library, and RTF and HTML are not tied to any of them in the list.

So the format you can offer is not a setting in the library; it is a function of what your server has installed.

PDF output is dompdf, not a native writer

The PDF entry in the requirements list is worth pulling out of the list, because it is the only optional item that is a whole library rather than a PHP extension.

The other optional items are PHP extensions. PDF is listed as the dompdf library and marked optional, used to write PDF.

That tells you two things. Writing PDF depends on an outside library rather than on PHPWord's own writers. And it tells you what the output will look like, since a document rendered by dompdf is a web page that happens to be paginated rather than a native word processor document.

For a report generator that is a feature. For anything where the recipient will open the file and adjust it in a word processor, the difference between the two is the thing to weigh.

The samples are a numbered curriculum

The samples directory contains 25 sample files numbered in a deliberate order, and the numbering is a reading order rather than an accident.

The first few cover the simplest cases in turn: simple text, tab stops, sections, text runs and multicolumn layout. Then footnotes, template row cloning, paragraph pagination and tables. Later samples move to images, list items, links, embedded objects, titles with a table of contents, watermarks, text breaks, background colours, table row rules, checkboxes, template blocks and reading ODF text.

Two of them read Word files, and they cover different generations of the format: one reads Word 2007 documents and one reads Word 97 documents; a third, Sample_24, reads ODF text.

The readme gives you a way to run them without installing anything into a project: launch PHP's built-in server in the samples directory and browse to a local address. That turns a directory of scripts into a browsable reference, which is a better answer to how do I do X than a documentation site search.

Composer, with an unreleased variant one word away

Installation is Composer, and there are two commands rather than one.

sh
composer require phpoffice/phpword

That gives the latest stable version. If you want the latest unreleased version, the constraint changes to the development branch of master:

sh
composer require phpoffice/phpword:dev-master

The project publishes to a package index, and the readme's badges point at it and at a coverage service, so both the install path and the test coverage are one click from the top of the page.

The unreleased variant is worth understanding rather than ignoring. Everything on the master branch that is not yet tagged is available through it, which means bug fixes land there first and a stable install may lag behind fixes you can already have.

Three licence files for one library

The licensing is stated in a single sentence: the project is open source and licensed under the terms of the LGPL version 3, with a link to a file named for the lesser licence text.

The repository root holds three licence-related files, which is more than a single-licence project needs. There is a general licence file, a file matching the LGPL lesser terms that the readme points at, and a copying file.

The reason for the split is the format of the licence rather than anything unusual about the project. The LGPL is a wrapper: a library can be used by a proprietary application as long as modifications to the library itself are made available. So a project distributing one library keeps both the main terms and the library-specific ones side by side.

The readme also states the project's aim, which is to be a high quality software product by incorporating continuous integration and unit testing. That claim is checkable from the tree.

One minor release a year, and a documented toolchain

The release history is three minor versions over about eighteen months: 1.2.0 in December 2023, 1.3.0 in September 2024, and 1.4.0 in June 2025. The last push to master is dated 26 October 2026, so the branch has moved well past the newest tag.

A yearly minor cadence for a library of this scope is worth noting before you depend on it. Nothing about it suggests abandonment, and the tree is full of current tooling, but a project on a 1.x line with annual minors should be planned for as a dependency rather than a foundation.

The tooling files describe what the maintainers actually run. There is a code style fixer configuration, a mess detector configuration, static analysis configuration with a baseline file beside it, a unit test configuration, and a distribution configuration file for the library itself. Documentation is built with its own static site generator configuration, and a changelog generator configuration sits at the repository root.

So the quality claim is backed by a conventional PHP toolchain rather than by an unusual one.

Editorial conclusion

PHPWord fits a PHP application that has to emit or ingest a real document rather than a rendered page, and that wants charts, footnotes, tables and templates without a conversion service. It does not fit someone who needs pixel-perfect layout matching, because the feature list is about document structure rather than visual fidelity. Before installing, check which optional PHP extensions your server has, since images and OOXML writing each need a different extension, and PDF output needs the dompdf library.

Frequently asked questions

How do I install PHPWord?

With Composer, requiring phpoffice/phpword for the latest stable release or phpoffice/phpword:dev-master for the latest unreleased version. You also need PHP 7.1 or newer, the XML parser extension, and the Laminas Escaper component, plus whichever optional extensions match the formats you intend to write.

How do I use PHPWord?

Create a document object, add a section to it, and then append everything inside that section, because any element appended must reside inside a section. The samples directory contains a numbered series from simple text through tables, images, templates and readers for older Word formats, and the readme shows how to browse them with PHP's built-in server.

What are the alternatives to PHPWord?

The readme names no alternative library. It does list the formats it supports, which are OOXML, the OpenDocument format, RTF, HTML and PDF, and the optional PHP extensions each one needs, which is the practical comparison point when choosing a library for a given output format.

Official sources

  1. Issues
  2. PHPOffice/PHPWord on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/phpoffice-phpword.svg)](https://hysenlabs.com/projects/phpoffice-phpword)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/phpoffice-phpword.svg)](https://hysenlabs.com/projects/phpoffice-phpword)

Was this useful?