Blog

Creating custom PDF documents is a very time-consuming task in projects. In order to improve this process there are various approaches - one of the most common ones by creating a HTML document that gets converted to PDF. At the end of the day this solution is not always the best as every new PDF needs to be implemented as a HTML document again before you can start.

Intro

You can find few solutions for editing word document templates with PHP on the Internet, the most popular ones being: PHP Word, phpdocx and LiveDocx. Since PHP Word is the only one that is free, I gave it a go.

PHP Word authors say about PHP Word: “PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft Office Open XML (OOXML or OpenXML), OASIS Open Document Format for Office Applications (OpenDocument or ODF), Rich Text Format (RTF), HTML, and PDF”.

The tested version is v0.12.1. Its supported formats are, better known by their extensions, Office Open XML - .docx and .docm, Open Document - .odt and .fodt.

Even though the PHP Word can be found on both  CodePlex and GitHub , it has moved to GitHub some time ago. GitHub is also used for posting bug issues. Documentation is on Read the Docs.

Also, in case someone needs a free solution for manipulating spreadsheets, the same team, the PHP Office has a PHP Excel library. I will now explain to you how to set up and use PHP Word for editing .docx templates.

doc to pdf

PHP Word Setup

This part explains how to set up PHP Word. I hereby start with a list of prerequisites and will then explain how to install PHP Word on a Linux Server, and finally, how to use it.

Requirements

Before we start with different steps, we need to consider which prerequisites are necessary. First you need to be able to set the PHP Word on your Linux web server. Therefore you need:

  • PHP 5.3+
  • PHP XML Parser extension (it is enabled by default)
  • Composer (optional, but recommended)
  • PHP Phar extension
    • comes pre-installed with required version of PHP
    • to enable the Phar extension, uncomment or add following line if it is not present in php.ini file:
  • OpenSSL package
  • PHP Openssl extension (comes pre-installed with PHP)
    • comes with OpenSSL package
    • to enable OpenSSL extension, uncomment or add following line if it is not present in php.ini file:

Installation

The recommended way to install PHP Word is to use a composer, but if you prefer not to use the composer, even though you know you should use it, you can download or clone project from GitHub .

“Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.” “It deals with 'packages' or libraries, but it manages them on a per-project basis, installing them in a directory (e.g. vendor) inside your project. By default it does not install anything globally². Composer is using composer.json file to know which packages or libraries it needs to download.

To install PHP Word using composer way, you need to add „phpoffice/phpword“ : „dev-master“ to your composer.json file under the require key. If you don't have composer.json file, simply create one in your project root with following content:

{
"require": {
"phpoffice/phpword": "dev-master"
}
}

In both cases, after the composer.json file is saved, issue the composer install command in terminal in the directory where you placed it.

Including PHP Word to your specific project

To include PHP Word to your project, you need to require the PHP Word Autoloader.php from src/PHPWord folder and register it:

require_once 'src/PhpWord/Autoloader.php';
\PhpOffice\PhpWord\Autoloader::register(); 

Editing templates

You probably found yourself in a situation where you need some template documents with only a few different values for each user, receipt or something else. That is exactly the situation where PHP Word would come very handy and make your work effortless.

Thereby it is the only requirement to save the document .docx extension. Placeholders for variables or arrays in the template are defined the same way, ${variableName} or ${arrayName}. Placeholder for array MUST be in a table cell, so it can be cloned later. This is good, because it enables you to later insert as many entries to one placeholder programmatically.

To replace the placeholders with your variables, you need to:

Open template:
$template = new\PhpOffice\PhpWord\TemplateProcessor(‚folder/file.docx‘);

Replace your placeholders with your variables:
$template->setValue(‚variableName‘, ‚MyVariableValue‘);

Replace your placeholders with your arrays:
3a: first you need to clone your array placeholder to the count of your array
3b: $template->cloneRow(‚arrayName‘, count($array));
3c: and then you need to give all of them a values
3d: for($number = 0; $number < count($array); $number++) {
    $template->setValue(‚arrayName#‘.($number+1), htmlspecialchars($array[$number], ENT_COMPAT, ‚UTF-8‘));
}

And save the modified file
$template->saveAs(‚folder/result.docx‘);

Converting to PDF

There is an option to integrate dompdf with PHP Word to convert file to PDF after editing template, but it won't give expected result of a well-formated document. If you want to achieve the best results, the easiest thing to do is to install LibreOffice on your server. If you are on shared hosting, you probably won't be able to do that, so you'll need either Virtual Private Server (VPS) or dedicated hosting. VPS hosting is not that expensive these days and if you need converting files to PDF, you will have to get it and set it up. If you bump into problems when trying to convert with LibreOffice, you still have great backup – unoconv.

Universal Office Converter (unoconv) is a command line tool to convert any document format that LibreOffice can import to any document format that LibreOffice can export. It makes use of the LibreOffice’s UNO bindings for non-interactive conversion of documents.

After you have installed LibreOffice on your server, you can see if it works by doing the following: Navigate to folder where you have some of your document files and issue following command:

libreoffice --headless --convert-to pdf /path/to/document/file --outdir /desired/output/directory

or if you want to issue it from PHP:

shell_exec('libreoffice --headless --convert-to pdf /path/to/document/file --outdir /desired/output/directory');

If you get PDF after issuing that command, you are good to go and everything works. However, there are two possible problems I have already warned you about.

The first problem is:

“[Java framework] Error in function createSettingsDocument (elements.cxx).javaldx failed!

Warning: failed to read path from javaldx”

This one can be solved. You need to create folder .config in home folder of your apache user. For CentOS, Debian and Ubuntu this is /var/www. You will neeed to use user with sudo rights (or root user, not recommended) to issue required commands. Navigate to required folder:

cd /var/www

and create folder:

mkdir .config    

After that, you need to make apache user and group owner of that newly created folder. Apache user and group are apache for CentOS and www-data for Ubuntu and Debian. For CentOS

sudo chown -R apache:apache /var/www/.config

or for Debian/Ubuntu:

sudo chown -R www-data:www-data /var/www/.config


The second problem starts with:

“Error: Please verify input parameters…”

For this problem, I didn't find any working solutions, even though there are some proposed online. If you have time, check them, but I wouldn't hope too much. Should you be able to find a solution, please let me know in the comments on this article.

If you had no luck with LibreOffice, you can still use unoconv for same result, with few more tunings.

After you install it, you will need to grant sudo rights to apache user and group for unoconv (only for unoconv!) since it requires sudo rights to be ran. Again, you will need to run following command with user with sudo rights:

sudo visudo

When it opens, scroll down to the bottom and find a line which looks like this:

root ALL=(ALL:ALL) ALL

You should add following below that line for CentOS:

apache ALL=NOPASSWD:/usr/bin/unoconv
%apache ALL=NOPASSWD:/usr/bin/unoconv

or for Debian/Ubuntu:

www-data ALL=NOPASSWD:/usr/bin/unoconv
%www-data ALL=NOPASSWD:/usr/bin/unoconv

This enables your apache user and group to run only unoconv with sudo rights with no password required.

With that done, you set unoconv. You can try it by issuing command:

sudo unoconv -f pdf /path/to/input/file

This command will convert the input file to PDF and save it to the current folder. Or if you want to use it from PHP, just run it with shell_exec:

shell_exec('sudo unoconv -f pdf /path/to/input/file');

Results

As a result of this whole process, we get a pixel-perfect pdf document that we can send to clients.

The biggest advantage of this solution is that it saves hours of development. Everyone who was making any kind of PDFs, using any solution – either solution that write (or draw) directly to pdf or made HTML template first and then converted it to pdf will know how much time it consumes and that results are not always what we expect. Not to mention that if you already spent time creating PDF and then client wants some changes. It was a nightmare. With this solution, you can let clients create their own template and change it any time without giving you a headache.

Earlier we also wasted so much time on aligning PDFs, but now we established this as a team-wide service which all our future projects can rely on and we can use our saved time to do something smarter – anything is better than wasting hours on creating PDFs :)

I hope this tutorial helps you to improve your development of PDFs in PHP. If you have any questions, feel free to contact us and leave us a message.

Furthermore, if there are things you consider to be important for this tutorial, please feel free to let us know.

1 https://github.com/PHPOffice/PHPWord

2 https://getcomposer.org/doc/00-intro.md3

3 https://github.com/dagwieers/unoconv