Edit PDF Form fields with PHP

By\ \ Leo Daidone

  1. Home
  2. Engineering Blog
  3. Edit PDF Form fields with PHP

Intro

Today I’m going to present a use case of a client who requires a PHP application that can export PDF files filled with  collected data.

To illustrate, I will present and small example project in Laravel.

Setting environment up

Let’s start creating a Laravel project

composer create-project laravel/laravel PDFTest

The next step is create a docker container for this project.

version: '3.6'

services:

webserver:
    image: nginx:latest
    container_name: pdf_web
    env_file: ./docker/environment.env
    volumes:
      - ./:/code
      - ./docker/nginx/site.conf:/etc/nginx/conf.d/site.conf
      - ./docker/nginx/laravel.site.conf:/etc/nginx/conf.d/api.conf
      - ./docker/nginx/fastcgi.conf:/etc/nginx/fastcgi.conf
    ports:
      - "80:80"
      - "8888:80"

php:
    image: erdiko/php-fpm:latest
    container_name: pdf_php
    env_file: ./docker/environment.env
    volumes:
      - ./:/code
    ports:
      - "9000:9000"

PDF library

After some research, I opted for pdftk, since it seems to be the most widely used.

Pdftk is a cross-platform binary that provides a bunch of handy command line options to manipulate PDFs like get plain text content, list fields, list fields data, fill in forms, etc.

A simple entrypoint.sh script is used to install the pdftk.

#!/bin/bash

apt update && apt install -y pdftk;

php-fpm

that has to vi mapped and executed in the php services, getting something like this

php:
 image: erdiko/php-fpm:latest
 container_name: pdf_php
 env_file: ./docker/environment.env
 volumes:
 - ./:/code
 - ./docker/entrypoint.sh:/usr/local/etc/php/entrypoint.sh
 ports:
 - "9000:9000"
 entrypoint: /usr/local/etc/php/entrypoint.sh

How to integrate in PHP

Here we will install php-pdftk package. Php-pdftk is a php package that relays on pdftk to manipulate PDF documents from php applications.

composer require mikehaertl/php-pdft

that provides a PHP class, named PDF, with all needed methods to work with PDF files.

Let’s put hands on the code

The first step is create controller, which I named it PdfEditor.


Below is how the implementation looks like,

<?php

namespace App\Http\Controllers;

use mikehaertl\pdftk\Pdf;

class PdfEditor extends Controller
 {
 /**
 * Show the application dashboard.
 *
 * @return \Illuminate\Http\Response
 */
 public function index()
 {
 return view('pdftest.upload');
 }

public function store(Request $request)
 {
 $uploadedFile = $request->file('pdf_file');
 $filename = $uploadedFile->getClientOriginalName();

$request->session()->put('current_pdf', $filename);

Storage::disk('local')->putFileAs(
 'files/'.$filename,
 $uploadedFile,
 $filename
 );

return redirect()->back()->with('success', 'Your file is submitted Successfully');
 }

public function preview()
 {
 if(Session::has('current_pdf')) {
 $filepath = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix() . 'files/'. Session::get('current_pdf');
 $filename = $filepath . '/' . Session::get('current_pdf');

return response(file_get_contents($filename))->withHeaders([\
 'Content-Type' => 'application/pdf'\
 ]);
 }
 return redirect()->back()->with('error', 'Sorry. File not found.');
 }

public function edit()
 {
 $filepath = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix() . 'files/'. Session::get('current_pdf');
 $filename = $filepath . '/' . Session::get('current_pdf');
 $pdf = new Pdf($filename);

$fields = $pdf->getDataFields(true)->__toArray();

return view('pdftest.edit')->with('fields',$fields);
 }

public function save(Request $request)
 {
 $filepath = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix() . 'files/'. Session::get('current_pdf');
 $filename = $filepath . '/' . Session::get('current_pdf');
 $target = $filepath . '/filled_' . Session::get('current_pdf');
 $pdf = new Pdf($filename);

$inputs = $request->all();
 unset($inputs['_token']);
 foreach ($inputs as $field=>$value) {
 $data[str_replace('_',' ',$field)] = $value;
 }

$pdf->fillForm($data)
 ->needAppearances();

if (!$pdf->saveAs($target)) {
 $error = $pdf->getError();
 dd($error);
 }
 return response(file_get_contents($target))->withHeaders([\
 'Content-Type' => 'application/pdf'\
 ]);
 }
 }

We will also need two views, one to upload the PDF and the other to create a dynamic form that will allow us to edit the content of the PDF form.

Below is how the edit form looks like

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">PDF Test</div>

<div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif

@if (session()->has('success'))
                            <div class="alert alert-success">
                                <ul>
                                    <li>{!! session()->get('success') !!}</li>
                                </ul>
                            </div>
                        @endif

<form method="POST" action="/pdftest/save" aria-label="{{ __('Save Changes') }}">
                            @csrf

<table class="table table-bordered table-striped">
                                <thead>
                                    <tr>
                                        <td>Name</td>
                                        <td>Type</td>
                                        <td>Value</td>
                                    </tr>
                                </thead>
                            @foreach($fields as $field)
                                <tbody>
                                    <tr>
                                        <td>{{$field['FieldName']}}</td>
                                        <td>{{$field['FieldType']}}</td>
                                        <td>{{json_encode($field['FieldValue'])}}</td>
                                    </tr>
                                </tbody>
                            @endforeach
                            </table>
                            {{--@foreach($fields as $field)--}}
                                {{--<div class="form-group row">--}}
                                    {{--<label for="{{$field['FieldName']}}">{{ __($field['FieldName']) }}</label>--}}
                                    {{--@switch($field['FieldType'])--}}
                                        {{--@case('Text')--}}
                                            {{--<div class="col-md-6">--}}
                                                {{--<input type="text" id="{{$field['FieldName']}}" name="{{$field['FieldName']}}" value="{{json_encode($field['FieldValue'])}}">--}}
                                            {{--</div>--}}
                                        {{--@break--}}
                                        {{--@case('Choice')--}}
                                            {{--<div class="col-md-6">--}}
                                                {{--<select id="{{$field['FieldName']}}" name="{{$field['FieldName']}}" value="{{json_encode($field['FieldValue'])}}">--}}
                                                    {{--<option value="{{$field['FieldValue']}}">{{$field['FieldValue']}}</option>--}}
                                                    {{--@foreach($field["FieldStateOption"] as $option)--}}
                                                        {{--<option value="{{$option}}" >{{__($option)}}</option>--}}
                                                    {{--@endforeach--}}
                                                {{--</select>--}}
                                            {{--</div>--}}
                                        {{--@break--}}
                                        {{--@case('Button')--}}
                                            {{--<div class="col-md-6">--}}
                                                {{--@if($field['FieldValue']=="1")--}}
                                                    {{--<input type="checkbox" id="{{$field['FieldName']}}" name="{{$field['FieldName']}}" value="{{$field['FieldValue']}}" checked>--}}
                                                {{--@else--}}
                                                    {{--<input type="checkbox" id="{{$field['FieldName']}}" name="{{$field['FieldName']}}" value="{{$field['FieldValue']}}">--}}
                                                {{--@endif--}}
                                            {{--</div>--}}
                                        {{--@break--}}
                                    {{--@endswitch--}}
                                {{--</div>--}}
                            {{--@endforeach--}}

<div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Save changes') }}
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Once you finish just click on Save Changes button that will fill the form and save a new filled PDF.

Final thoughts

I hope this simple example illustrate on how to handle projects that requires PDF form edition.

Thank you for reading and see in the next post.

Tags: Laravel, pdf, pdf forms, pdf-tk, php, programming

Categories: PHP, Programming

Comments

Disqus Recommendations

We were unable to load Disqus Recommendations. If you are a moderator please see our troubleshooting guide.

  • 8 years ago
  • 4 comments

An overview and examples of debugging your PHP application with the use of …

  • 9 years ago
  • 1 comment

In the second part of our NPM & Angular CLI series we discuss how we turned …

  • 8 years ago
  • 1 comment

A real world example of an Angular observable

  • 9 years ago
  • 3 comments

Creating a custom application with Angular CLI is easy and fun. …

  • 9 years ago
  • 10 comments

Using components is a fantastic way to include 3rd party libraries like …

  • 7 years ago
  • 3 comments

The future of jQuery

  • 8 years ago
  • 1 comment

Videojs component with Vuejs

  • 10 years ago
  • 1 comment

Remote PHP Debugging with Xdebug

Disqus Comments

We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

What do you think?

4 Responses

Upvote

Funny

Love

Surprised

Angry

Sad

G

Join the discussion…

Comment

Log in with
or sign up with Disqus or pick a name

Disqus is a discussion network

  • Don't be a jerk or do anything illegal. Everything is easier that way.

Read full terms and conditions

This comment platform is hosted by Disqus, Inc. I authorize Disqus and its affiliates to:

  • Use, sell, and share my information to enable me to use its comment services and for marketing purposes, including cross-context behavioral advertising, as described in our Terms of Service and Privacy Policy, including supplementing that information with other data about me, such as my browsing and location data.
  • Contact me or enable others to contact me by email with offers for goods or services
  • Process any sensitive personal information that I submit in a comment. See our Privacy Policy for more information

Acknowledge I am 18 or older

Favoriting means this is a discussion worth sharing. It gets shared to your followers' Disqus feeds, and gives the creator kudos!

Find More Discussions

Share

K

I tried to achive what state in this tutorial.

But i have a main issue that the pdftk can not write into the tmp folder:

Warning: copy(filled.pdf): failed to open stream:

Permission denied in /var/www/html/pdfa/vendor/mikehaertl/php-pdftk/src/Pdf.php on line 555

its seem tmp dolder is not writable but it has 777 chmod so totally dont understand whats the issue with it.

Do you have any idea?

see more

Show more replies

Load more comments

live.rezync.com

live.rezync.com is blocked

This page has been blocked by an extension

  • Try disabling your extensions.

ERR_BLOCKED_BY_CLIENT

Reload

This page has been blocked by an extension

pippio.com

pippio.com is blocked

This page has been blocked by an extension

  • Try disabling your extensions.

ERR_BLOCKED_BY_CLIENT

Reload

This page has been blocked by an extension

See how we can help

Lets talk!

Contact Us

Stay up to date on the latest technologies

Join our mailing list, we promise not to spam.

Email AddressJoin