Download the PHP package dskripchenko/php-docx without Composer
On this page you can find all versions of the php package dskripchenko/php-docx. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dskripchenko/php-docx
More information about dskripchenko/php-docx
Files in dskripchenko/php-docx
Package php-docx
Short Description The HTML layer for PHPWord pipelines and a standalone DOCX-HTML round-trip library: read arbitrary Word/Google Docs/LibreOffice/PHPWord documents to a typed AST and clean HTML, convert HTML to DOCX, detect MERGEFIELD/content-control/{{placeholder}} template variables. Pure PHP, zero dependencies.
License MIT
Informations about the package php-docx
dskripchenko/php-docx
π English Β· δΈζ
The HTML layer for your PHPWord pipeline β and a standalone
DOCX β HTML round-trip library. Pure-PHP: read arbitrary Word /
Google Docs / LibreOffice / PHPWord documents into a typed AST, turn
them into clean HTML, convert HTML into DOCX, detect template variables
(MERGEFIELD, content controls, {{placeholders}}). Works next to
PHPWord, not instead of it. No
external dependencies beyond standard PHP extensions.
Read this in other languages: English Β· Π ΡΡΡΠΊΠΈΠΉ Β· δΈζ Β· Deutsch
Table of contents
- Features
- php-docx and PHPWord
- Requirements
- Installation
- Quick start
- HTML β DOCX
- Programmatic builder
- DOCX β HTML / AST
- HTML β DOCX
- Programmatic builder API
- DOCX β HTML (Reader)
- Headers, footers & watermarks
- Sections
- Variable detection
- Length helpers
- AST overview
- Round-trip
- Architecture
- Development
- License
Features
- HTML β DOCX writer β full set of typical layout elements (paragraphs/headings/tables/lists/images/links/fields), inline-style resolution, custom heading registry.
- DOCX β HTML reader β parses arbitrary Word/Pages/LibreOffice documents into a typed AST, then serialises back to HTML with inline styles. Style cascade (docDefaults β named β direct), theme colors, numbering reconstruction, vMerge/gridSpan collapse, watermark detection (VML + DrawingML).
- Fluent programmatic builder β
DocumentBuilderwith closure scopes for nested structures (tables, lists, headers). - Variable detection β MERGEFIELD, SDT content controls, configurable
text patterns (
{{x}},${x},%x%). - Multi-header/footer β default / first-page / even-pages variants
with automatic
<w:titlePg/>and<w:evenAndOddHeaders/>plumbing. - Sections β several per document, each with its own page setup (a preset paper size or any custom size), start (new page, continuous, even or odd page) and headers/footers; read back section by section.
- Floating pictures β positioned on the page, margin or paragraph, in front of or behind the text, with wrapping; from a header they repeat on every page.
- Round-trip safe β read DOCX β AST β write DOCX produces a valid document; bytes-level differences are limited to whitespace/ordering.
- PHP 8.2+ β
readonlyvalue-objects, named arguments, constructor promotion, enums. - Zero composer dependencies.
Out of scope
Tracked changes, comments, embedded charts, OLE objects, footnotes/endnotes, SmartArt, math equations (OMML), form fields, custom XML parts.
Examples
Runnable scripts with committed output live in
examples/: HTML β DOCX with headers and
watermarks, the fluent builder, DOCX β HTML import, template-variable
detection and substitution, round-trip stability, CSS inlining, and the
PHPWord bridge.
php-docx and PHPWord
PHPWord is the established library for building Word documents in PHP. php-docx does not replace it β it adds the two things PHPWord is weakest at: reading arbitrary DOCX (with a full style cascade) and HTML in both directions. Use both, each for what it does best.
What php-docx adds next to PHPWord:
- reading real-world DOCX (Word, Google Docs, LibreOffice, PHPWord output) into a typed AST β verified continuously on an external corpus, see the reader-fidelity dashboard;
- DOCX β clean HTML with inline styles (style cascade, theme colours, numbering, merged cells);
- HTML β DOCX;
- template-variable detection (MERGEFIELD, SDT content controls,
{{x}}/${x}/%x%patterns).
What php-docx deliberately does not do (PHPWord or other tools do): ODF/RTF/PDF output, tracked changes, comments, footnotes/endnotes, charts, OMML math, form fields.
Zero-integration recipe β works today, no bridge required. PHPWord writes the file, php-docx reads the bytes:
A typed object-level bridge (PhpWordBridge::toHtml($phpWord), HTML
import into PHPWord objects, reading straight into PHPWord models) ships
separately as dskripchenko/php-docx-phpword.
Requirements
- PHP 8.2+
ext-zip,ext-dom,ext-mbstring
Installation
Quick start
1. HTML β DOCX
2. Programmatic builder
3. DOCX β HTML / AST
HTML β DOCX
Input HTML must use inline styles only (no <style> blocks). Use a
CSS-inliner upstream if needed.
Supported elements
| Category | HTML tags |
|---|---|
| Text blocks | <p>, <h1..h6>, <div>, <pre>, <blockquote> |
| Inline marks | <strong>/<b>, <em>/<i>, <u>, <s>/<del>, <sup>, <sub>, <mark> |
| Code/teletype | <code>, <kbd>, <samp>, <var>, <cite>, <dfn>, <q>, <small> |
| Links | <a href> external, <a href="#anchor"> internal, <a id> bookmarks |
| Images | <img src="data:image/...;base64,..."> |
| Tables | <table>, <thead>/<tbody>, <tr>, <th>/<td>, <colgroup>/<col>, <caption>, colspan, rowspan |
| Lists | <ul>, <ol type="a/A/i/I" start="N">, <li value="N">, <dl>/<dt>/<dd>; Word numbering labels from .class::marker { content: β¦ counter(list-item) / counters(list-item, ".") β¦ } in a <style>; <li style="list-style-type:none"> holding only a nested list is a label-less parent (3. β 3.1.) |
| Custom tags | <page-number/>, <page-total/>, <current-date format="...">, <page-break> |
| Marker classes | class="page-number", class="page-total", class="page-break" β same fields, spelled so an HTML sanitizer keeps them |
| Layout | <hr>, <br>, <figure>/<figcaption> |
Inline styles
The converter understands style="β¦" properties:
- Run-level:
font-family,font-size,font-weight,font-style,text-decoration,color,background-color,letter-spacing - Paragraph-level:
text-align,margin,text-indent,line-height,border,padding,background-color - Table-level:
width,border,border-collapse - Cell-level:
width,padding,border,vertical-align,background-color
Custom tags
These become OOXML field codes (<w:fldSimple w:instr="PAGE">).
Custom heading styles
Stylesheets and classes
fromHtml() understands inline styles only. For HTML carrying
<style> blocks or class-based styling, use fromHtmlWithStyles() β
it first runs the document through an HtmlPreprocessor. The default
implementation inlines CSS via the optional
tijsverkoyen/css-to-inline-styles
package (composer require tijsverkoyen/css-to-inline-styles; php-docx
itself stays zero-dependency), and you can plug your own preprocessor:
Programmatic builder API
The Build namespace provides a fluent API for assembling DOCX
documents block by block, finalising to the same immutable AST that the
HTML pipeline produces.
DocumentBuilder
Entry point. Accumulates body, header/footer, watermark, page setup,
core properties (docProps/core.xml: title, author, dates).
Output is byte-for-byte reproducible: every ZIP entry carries
CoreProperties::$modified (UTC), or 1980-01-01 00:00:00 when it is not set.
ParagraphBuilder
Inside ->paragraph(fn ($p) => β¦):
Paragraph-level styling:
styleId() takes effect only for a style the document defines: Heading1..6,
ListParagraph, Caption, or one registered with StyleRegistry::paragraph().
Word shows a paragraph with an unknown id as Normal.
TableBuilder
Spans and merges:
ListBuilder
RunStyleBuilder
Used inside ->styled(text, fn (RunStyleBuilder) => β¦) or standalone via
RunStyleBuilder::new()->β¦->build().
Length helpers
Convert common units to OOXML twips (1 twip = 1/20 pt). Used wherever a twip int is expected.
Most builders expose unit-aware shortcuts:
- TableBuilder:
widthPt/widthMm/widthCm/widthInches,cellMarginsMm/cellMarginsPt,indent/indentMm/indentPt - TableCellBuilder:
widthPt/Mm/Cm/Inches,paddingMm/Pt/Cm/Inches - ColumnBuilder:
widthPt/Mm/Cm/Inches/Px - ParagraphBuilder:
indentMm/Cm/Pt/Inches,spacingPt/Mm - RunStyleBuilder:
fontSizePt
DOCX β HTML (Reader)
High-level: DocxReader
This runs the full pipeline: package unpack β styles resolve β body/header/footer parsing β vMerge/list reconstruction β image extraction β watermark detection β page setup.
Low-level: DocxPackageReader
If you need the raw OOXML parts:
Serializer: AST β HTML
HTML output uses inline styles, plus css for the labels of Word's
multilevel numbering (3.1., 4.1.): ::marker rules on the classes of
the list items, with <ol start> where a list broken off by a paragraph
numbers on. Re-loadable into the same library via
Html\Converter::fromHtml('<style>'.$imported->css.'</style>'.$imported->bodyHtml);
an application that inlines CSS first keeps the labels with
Converter::markerStyleOf($html).
Headers, footers & watermarks
Three header/footer types are supported per section: default, first
(title page), even (even pages). Word automatically renders the right
one based on page number.
The writer automatically:
- emits
<w:titlePg/>insectPrwhen first-page header/footer is set - emits
word/settings.xmlwith<w:evenAndOddHeaders/>when even header/footer is set
Watermark
Renders as a 45Β°-rotated VML text shape on every page.
Floating pictures
An Image with a position (an ImagePosition) floats (<wp:anchor>)
instead of sitting in the line of text. On each axis it is placed at an
offset in EMU from the page, the margin, the column or character
(horizontally), or the paragraph or line (vertically), or aligned there with
a PositionAlign. It is drawn in front of the text, or behind it with
behindText, and the text flows around it as wrap says (None, Square,
TopAndBottom); zOrder stacks floating pictures. The builder's
imageFromBytes(), imageFromDataUrl() and imageFromFile() take a
position.
A picture placed on the page from a header or footer is drawn on every page
that header governs: letterheads, page backgrounds, stamps. An offsetYEmu
without a position floats the picture that far below the top of its
paragraph. DocxReader reads the position back.
Sections
A document is one section unless the page setup or the headers change part
way through. newSection() ends the current section and starts the next:
the content, headers and footers added after it belong to the new one.
- A new section keeps the page setup unless given one, and starts on a new
page unless given a
SectionStart(Continuous,EvenPage,OddPage). - A section shows the previous section's headers and footers until it sets its own (Word's rule): an empty header list means "inherit", not "blank".
PageSetup(widthTwips:, heightTwips:)sets any page size; the page is landscape when it is wider than it is tall.- Without the builder:
new Document($first, followingSections: [$second, β¦]);Document::sections()lists them all. - Every section but the last ends with its
<w:sectPr>in the properties of its last paragraph (a paragraph is added when the section ends in a table).DocxReaderreads each section back with its own body, page setup, start and headers; the HTML serializer puts the bodies one after another, with a page break before each section that starts on a new page.
Variable detection
Scans an imported DOCX for three kinds of variables:
- MERGEFIELD β Word mail-merge native, both simple
<w:fldSimple>and complex<w:fldChar>form. - SDT content controls β
<w:sdt>with<w:tag w:val="...">. - Text patterns β configurable regexes (defaults:
{{name}},${name},%name%).
Detection runs across body + all headers + all footers. Results are
deduplicated by (source, name).
Length helpers
See Length helpers above. Conversion table:
| Unit | Twips | Pt | Notes |
|---|---|---|---|
| 1 twip | 1 | 0.05 | OOXML native |
| 1 pt | 20 | 1 | typography |
| 1 mm | ~57 | 2.83 | metric |
| 1 cm | ~567 | 28.35 | metric |
| 1 inch | 1440 | 72 | imperial |
| 1 px | 15 | 0.75 | CSS @ 96 DPI |
AST overview
All elements live under Dskripchenko\PhpDocx\Element namespace.
| Element | Type | Notes |
|---|---|---|
Document |
root | { section: Section, watermarkText: ?string, coreProperties: ?CoreProperties, followingSections: Section[] } |
Section |
container | { body, header, footer, pageSetup, firstHeader, firstFooter, evenHeader, evenFooter, start: SectionStart } |
Paragraph |
BlockElement | { children: InlineElement[], style: ParagraphStyle, headingLevel: ?int, styleId: ?string } |
Run |
InlineElement | { text: string, style: RunStyle } |
Hyperlink |
InlineElement | { href: ?string, anchor: ?string, children: InlineElement[] } |
Bookmark |
InlineElement | { name: string, children: InlineElement[] } |
Image |
both | { binary, format, widthEmu, heightEmu, altText, offsetYEmu, position: ?ImagePosition } |
Field |
InlineElement | { instruction: string, style: RunStyle } |
LineBreak, PageBreak, HorizontalRule |
both | marker elements |
Table |
BlockElement | { rows: TableRow[], style, caption, gridColumnsTwips } |
TableRow |
element | { cells: TableCell[], isHeader, heightTwips, cantSplit, heightRule } |
TableCell |
element | { children: BlockElement[], style: CellStyle } |
ListNode |
BlockElement | { items: ListItem[], ordered, format, startAt } |
ListItem |
element | { children: InlineElement[], nestedList: ?ListNode } |
Styles live under Dskripchenko\PhpDocx\Style:
RunStyleβ font (andfontFamilyEastAsiafor CJK text), weight, italic, color, size, highlight, β¦ParagraphStyleβ alignment, indents, spacing, borders, pagination (keepWithNext, keepLines, pageBreakBefore, widowControl)CellStyleβ width, padding, borders, valign, gridSpan, rowSpanTableStyleβ width, borders, alignment, cell margins, layout, indent (indentTwips)PageSetup,PaperSize,Orientation,Alignment,VerticalAlign,BorderStyle,Border,BorderSet
Round-trip
The library targets semantic round-trip safety, not byte equality β content, structure and styling survive, but XML ordering and whitespace may differ.
In-scope round-trip features:
- Paragraphs/headings with all run formatting
- Tables with
vMerge/gridSpanreconstruction - Lists (bullet/decimal/letter/roman) with arbitrary nesting
- Images with EMU sizes and alt text
- Hyperlinks (external + internal anchors) and bookmarks
- Headers/footers (default/first/even) and watermarks
- Field codes (PAGE, NUMPAGES, DATE, MERGEFIELD)
- Page setup (size, orientation, margins)
Out-of-scope features are silently dropped (footnotes, comments, equations, etc.).
Architecture
The same Document AST is shared by HTML conversion, programmatic
construction and DOCX reading β every entry/exit point operates on
typed value-objects.
Conformance
Every push validates the writer's output externally, not just against our own reader:
- ECMA-376 Transitional XSD β every WordprocessingML part (document, styles, numbering, headers, footers) is validated with xmllint against the official schemas (fetched from ecma-international.org, SHA-pinned);
- LibreOffice headless converts the reference document to PDF β a real-world consumer, not a mock;
- python-docx opens it and extracts the expected content β an independent reader implementation.
Reproduce locally:
Development
License
MIT β see LICENSE.
All versions of php-docx with dependencies
ext-dom Version *
ext-mbstring Version *
ext-zip Version *