[PHP] A story about outputting PDF with TCPDF + FPDI

Introduction

As the title says I tried to output PDF using the ** TCPDF ** and ** FPDI ** libraries. This time I will execute it from the command line.

Main story

Environment

Please prepare an environment where PHP and Composer can be used as you like.

Docker The Docker environment I used this time is as follows (partially omitted).

yml:./docker-compose.yml


version: '3'
services:
 php:
   build: ./php
   volumes:
     - ./work:/home/work

./php/dockerfile


FROM php:7.3-fpm
COPY php.ini /usr/local/etc/php/

# Composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
  && php -r "if (hash_file('sha384', 'composer-setup.php') === '795f976fe0ebd8b75f26a6dd68f78fd3453ce79f32ecb33e7fd087d39bfeb978342fb73ac986cd4f54edd0dc902601dc') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
  && php composer-setup.php \
  && php -r "unlink('composer-setup.php');" \
  && mv composer.phar /usr/local/bin/composer

ini:./php/php.ini


date.timezone = "Asia/Tokyo"

Composer When the launch is complete, enter the php container and Install the library in Composer.

In addition to the library, the description of autoload is also added.

/home/work/src/composer.json


{
    "require": {
        "setasign/fpdi": "^2.3",
        "tecnickcom/tcpdf": "^6.3"
    },

    "autoload": {
        "psr-4": {
            "Classes\\" : "classes/"
        }
    }
}

Once the installation is complete, you're done.

# cd /home/work/src
# composer install

Implementation

file organization

# cd /home/work/

# ls /home/work/output/pdf/fileYYYYmmdd-HHiiss #PDF output file
# ls /home/work/src/resources/font/ipam.ttf #Font storage location
# ls /home/work/src/resources/pdf/templete.pdf #PDF template storage location
# ls /home/work/bin/make-pdf.php #Source to run on the command line
# ls /home/work/src/bootstrap.php #Start-up file(Omitted)
# ls /home/work/src/classes/MyTcpdf.php #TCPDF usage class
# ls /home/work/src/classes/common/DynamicProperty.php #Dynamic class(Omitted)
# ls /home/work/src/classes/MyTcpdf/FontColor.php #Font color class(Omitted)

template

It's a very simple PDF template file.

image.png

Source

/home/work/bin/make-pdf.php


<?php

require_once __DIR__ . '/../src/bootstrap.php';

use Classes\MyTcpdf;
use Classes\MyTcpdf\FontColor;

//Output without using a template
$myTcpdf = new MyTcpdf();
$myTcpdf->addPage();
$myTcpdf->setText('Output without using a template', 10, 20, new FontColor(0, 255, 0));
$myTcpdf->outputPdfFile();

//Output using template
$myTcpdfTmp = new MyTcpdf();
$myTcpdfTmp->addPageWithTemplete(1);
$myTcpdfTmp->setText('Output using template', 10, 20, new FontColor(255, 0, 0));
$myTcpdfTmp->outputPdfFile();

/home/work/src/classes/MyTcpdf.php


<?php

namespace Classes;

use TCPDF_FONTS;
use setasign\Fpdi\Tcpdf\Fpdi;
use Classes\MyTcpdf\FontColor;

class MyTcpdf
{
    //Output file
    const OUTPUT_FORMAT_CHAR = 'F';
    const OUTPUT_FILE_DIR = __DIR__.'/../../output/pdf/';
    const OUTPUT_FILE_NAME = 'file';

    // PDF
    const PDF_ORIENTATION = 'P';
    const PDF_UNIT = 'mm';
    const PDF_SIZE = 'A4';
    const PDF_TEMPLETE = __DIR__.'/../resources/pdf/templete.pdf';

    //Font file
    const FONT_FILE_NAME = __DIR__.'/../resources/font/ipam.ttf';

    /**
     *constructor
     */
    public function __construct()
    {
        $this->fpdi = new Fpdi(self::PDF_ORIENTATION, self::PDF_UNIT, self::PDF_SIZE);
        $this->fpdi->SetMargins(0, 0, 0);
        $this->fpdi->SetFont($this->getFont(), '', 32);
    }

    /**
     *Set the output character
     * @param _text string
     * @param _x X coordinates
     * @param _y Y coordinates
     * @param _h height
     */
    public function setText(string $_text, int $_x, int $_y, FontColor $_fontColor, int $_h = 0)
    {
        $this->fpdi->SetTextColor($_fontColor->R, $_fontColor->G, $_fontColor->B);
        $this->fpdi->SetXY($_x, $_y);
        $this->fpdi->Write($_h, $_text);
    }

    /**
     *Get the font to add
     */
    private function getFont()
    {
        return TCPDF_FONTS::addTTFfont(self::FONT_FILE_NAME);
    }

    /**
     *Get the output file name
     * @return string filename
     */
    private function getOutputFilename()
    {
        return self::OUTPUT_FILE_DIR . self::OUTPUT_FILE_NAME . date("Ymd-His"). '.pdf';
    }

    /**
     *Add page
     */
    public function addPage()
    {
        $this->fpdi->AddPage();
    }

    /**
     *Add a template-based page
     */
    public function addPageWithTemplete($_pageNum)
    {
        $this->fpdi->SetSourceFile(self::PDF_TEMPLETE);
        $page = $this->fpdi->importPage($_pageNum);
        $this->fpdi->AddPage();
        $this->fpdi->useTemplate($page, null, null, null, null, true);
    }

    /**
     *PDF file output
     */
    public function outputPdfFile()
    {
        $this->fpdi->Output(
            $this->getOutputFilename(),
            self::OUTPUT_FORMAT_CHAR
        );
    }
}

Execution command

php /home/work/bin/make-pdf.php

Execution result

The file was output as follows.

No template There is a template
image.png image.png

At the end

Since you can output characters on the PDF template, you can output only the necessary information without changing the format. It seems that it can be used for files such as rosters, invoices, receipts, etc. where only specific parts change.

Recommended Posts

[PHP] A story about outputting PDF with TCPDF + FPDI
A story about trying to get along with Mockito
A story about reducing memory consumption to 1/100 with find_in_batches
A story about developing ROS called rosjava with java
A story stuck with NotSerializableException
A confused story about a ternary operator with multiple conditional expressions
[Note] A story about changing Java build tools with VS Code
A story about hitting the League Of Legends API with JAVA
A story about having a hard time aligning a testing framework with Java 6
A little addictive story with def initialize
A story about saving an image with carrierwave in a nested form using a form object.
A story about creating a library that operates next-generation sequencer data with Ruby ruby-htslib
Read a string in a PDF file with Java
About getting a tens digit with "(two-digit integer) / 10% 10"
A story about Java 11 support for Web services
A story about the JDK in the Java 11 era
A story about a very useful Ruby Struct class
A story about Apache Wicket and atomic design
A story about making a Builder that inherits the Builder
A story about trying to operate JAVA File
A story packed with Java's standard input Scanner
A story about a new engineer reading a passion programmer
[Jackson] A story about converting the return value of BigDecimal type with a custom serializer.
A story that got stuck with an error during migration in docker PHP laravel
A story about PKIX path building failed when trying to deploy to tomcat with Jenkins
A story about an error collating checksum values after npm install with Laravel Homestead