Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with PDF in PHP

Short

What I want to do is, to prepare PHP generated result for print with strong rules.

Tried all possible ways with css+html: set dimensions in px, mm, cm. Nothing helped. Each browser, even each printer printed absolutely different paper results (tried both with & w/o border print. also didn't get result). After long research, found that CSS is not best way for this purpose and better way - to use pdf creation functionality with PHP. So, installed TCPDF. But can't get it work with logical part that I created for HTML output.

What I want to get

  • Table's first and last rows' margin from top and bottom sides of paper must be 11 mm
  • Margin between rows' 0 mm
  • Table's rows must be at 4 mm from left and right sides of paper
  • 2 mm between every column
  • 38 mm width x 21.2 mm height each cell
  • 13 x rows, 5 x columns, 13x5=65 cells
  • Each table in new page. In other words - after each table page break
  • In each cell Code 39 Barcode (value must be $id)
  • Only tables in PDF result - no header, no footer, no title ... etc

Here is more detailed explanation on image:

enter image description here

What I'm getting

After form submission, processing in php side takes too long - about minute and opens blank page instead of PDF result.

Code:

(Code is not so huge, comments are making it look like so:)

<?php
require_once('tcpdf/config/lang/eng.php');
require_once('tcpdf/tcpdf.php');

// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

$pdf->SetPrintHeader(false);
$pdf->SetPrintFooter(false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('John Smith');
$pdf->SetTitle(false);
$pdf->SetSubject(false);
$pdf->SetKeywords(false);

// set default header data.set all false because don't want to output header footer
$pdf->SetHeaderData(false, false, false, false);

// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));

// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

//set margins
$pdf->SetMargins(4, 11, 4);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

//set some language-dependent strings
$pdf->setLanguageArray($l);

// ---------------------------------------------------------
// set font
$pdf->SetFont('helvetica', '', 10);

// add a page
$pdf->AddPage();

// define barcode style
$style = array(
    'position' => '',
    'align' => 'C',
    'stretch' => false,
    'fitwidth' => true,
    'cellfitalign' => '',
    'border' => true,
    'hpadding' => 'auto',
    'vpadding' => 'auto',
    'fgcolor' => array(0, 0, 0),
    'bgcolor' => false, //array(255,255,255),
    'text' => true,
    'font' => 'helvetica',
    'fontsize' => 8,
    'stretchtext' => 4
);

ob_start();
?>



<style type="text/css">

    table { 

        width: 100%;          

        border-collapse: collapse;

    }

    td img {
        height:10mm;
    }

    td {
        padding: 0 1mm 0 1mm;
        vertical-align:middle;              
    }

    .cell {
        width: 38mm;
        height:21mm;
        font-style: bold;
        text-align: center; 
    }

    tr    { 
        height:21mm;
        margin:0;
        padding:0;            
    }


</style>

<?php

$i = 0;
$item = new item($db);
foreach ($_POST['checkbox'] as $id) {
    $details = $item->getDetails($id);
    $qt = (isset($_POST['qt'])) ? $_POST['qt'] : $details['qt'];
    for ($cnt = 1; $cnt <= $qt; $cnt++) {
        // check if it's the beginning of a new table
        if ($i % 65 == 0)
            echo '<table>';

        // check if it's the beginning of a new row
        if ($i % 5 == 0)
            echo '<tr>';

        echo '<td><div class="cell">www.fety.fr<br/>';
        $pdf->Cell(0, 0, 'CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9', 0, 1);
        $pdf->write1DBarcode($id, 'C39', '', '', '', 18, 0.4, $style, 'N');
        $pdf->Ln();
        echo '<br/>' . $details['hcode'] . '</div></td>';

        // check if it's the end of a row
        if (($i + 1) % 5 == 0)
            echo '</tr>';

        // check if it's the end of a table
        if (($i + 1) % 65 == 0)
            echo '</tr></table>';

        $i++;
    }
}

// if the last table isn't full, print the remaining cells
if ($i % 65 != 0) {
    for ($j = $i % 65; $j < 65; $j++) {
        if ($j % 65 == 0)
            echo '<table>';
        if ($j % 5 == 0)
            echo '<tr>';
        echo '<td></td>';
        if (($j + 1) % 5 == 0)
            echo '</tr>';
        if (($j + 1) % 65 == 0)
            echo '</table>';
    }
}

$markup = ob_get_clean();

// output the HTML content
$pdf->writeHTML($markup, true, false, true, false, '');



// reset pointer to the last page
$pdf->lastPage();

// ---------------------------------------------------------
//Close and output PDF document
$pdf->Output('bcsheet.pdf', 'I');
?>

Script works like that:

  1. User selects items' checkboxes
  2. After form submission, PHP gets values of checked checkboxes via Ajax
  3. In foreach loop, PHP gets quantities of each item from database.
  4. Generated table
like image 683
heron Avatar asked Feb 12 '12 11:02

heron


2 Answers

here is an html/css to pdf converter library http://www.mpdf1.com/mpdf/

This has it's own html/css parser and thus will yield the same result in all browser.

<?php

$html = '
    <html>
    <head>
    <style>
        table {
        width: 100%;
            border-collapse: collapse;
        }       
        tr {

        }
        td {
            width: 38mm;
            height: 21.2mm;
            margin: 0 1mm;
            text-align: center;
            vertical-align:middle; 
        }
    </style>
    </head>
    <body>
    <table>';

    for ($i = 0; $i < 13; $i++)
    {
        $html .= '<tr>';
        for($j = 0; $j < 5; $j++)
        {
            $html .= '<td><barcode code="TEC-IT" type="C39" class="barcode" /></td>';
        }
        $html .= '</tr>';
    }       

$html .= '</table>
    </body>
    </html>';

    include("MPDF53/mpdf.php");

    $mpdf = new mPDF('c', 'A4', '', '', 4, 4, 10.7, 10.7, 0, 0);

    $mpdf->SetDisplayMode('fullpage');

    $mpdf->list_indent_first_level = 0;

    $mpdf->WriteHTML($html,0);

    $mpdf->Output('test.pdf','I');
    exit;

?>
like image 57
redmoon7777 Avatar answered Sep 17 '22 08:09

redmoon7777


I think that if you're not getting a result at all, you likely are suppressing errors in a way you can't you're getting them with your script. Also, your approach with HTML is just not how it works; you can't interleave the TCPDF native cell calls with HTML; they're not "outputting" markup. So you're mixing two different, incompatible formats, that are going to two different buffers.

However, you code should still generate a PDF.

Note the last page, with your markup-generated content.

The only changes I made was to make it where I could run it without access to your data:

$i = 0;
//$item = new item($db);
//foreach ($_POST['checkbox'] as $id) {
for ($id = 0; $id < 1; $id++) {
    //$details = $item->getDetails($id);
    //$qt = (isset($_POST['qt'])) ? $_POST['qt'] : $details['qt'];
    $details = array('These are details');
    $qt = 50;
    for ($cnt = 1; $cnt <= $qt; $cnt++) {
        // check if it's the beginning of a new table
        if ($i % 65 == 0)
            echo '<table>';

        // check if it's the beginning of a new row
        if ($i % 5 == 0)
            echo '<tr>';

        echo '<td><div class="cell">www.fety.fr<br/>';
        $pdf->Cell(0, 0, 'CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9', 0, 1);
        $pdf->write1DBarcode($id, 'C39', '', '', '', 18, 0.4, $style, 'N');
        $pdf->Ln();
        echo '<br/>' . $details['hcode'] . '</div></td>';

        // check if it's the end of a row
        if (($i + 1) % 5 == 0)
            echo '</tr>';

        // check if it's the end of a table
        if (($i + 1) % 65 == 0)
            echo '</tr></table>';

        $i++;
    }
}

I get a PDF. It looks nothing like what you have in the image, but it does produce a PDF. I see that your code is about 90% similar to this example on the TDPDF site:

http://www.tcpdf.org/examples/example_027.phps

When I went in and made my own example, I was able to get a PDF that generally mimicked what you show in the photo. As you'll see in the code I have below, you have to work with the native TCPDF cell methods to get the barcode generation to work. It's not that hard; took me about 30 minutes to figure out how to produce a pdf.

The only thing I couldn't figure out was where the black line on the top comes from; it's somehow associated with the header, but I couldn't find where to turn it off. The code that's behind the second PDF:

<?php

require_once('tcpdf/config/lang/eng.php');
require_once('tcpdf/tcpdf.php');

// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

//set auto page breaks
$pdf->SetAutoPageBreak(TRUE);

//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

//set some language-dependent strings
$pdf->setLanguageArray($l);

$pdf->SetFont('helvetica', '', 10);

// define barcode style
$style = array(
    'position' => '',
    'align' => 'L',
    'stretch' => true,
    'fitwidth' => false,
    'cellfitalign' => '',
    'border' => true,
    'hpadding' => 'auto',
    'vpadding' => 'auto',
    'fgcolor' => array(0,0,0),
    'bgcolor' => false, //array(255,255,255),
    'text' => true,
    'font' => 'helvetica',
    'fontsize' => 8,
    'stretchtext' => 4
);

for ($o = 0; $o < 5; $o++) {
    $pdf->AddPage();

    $y = 10;

    for ($i = 0; $i < 13; $i++) {
        $x = 10;

        for ($p = 0; $p < 5; $p++) {
            // UPC-E
            $pdf->write1DBarcode('04210000526', 'UPCE', $x, $y, 37, 20, 0.4, $style);

            $x = $x + 38;
        }

        $y = $y + 21;

        $pdf->Ln();
    }
}

//Close and output PDF document
$pdf->Output('example_027.pdf', 'I');

?>
like image 38
Jared Farrish Avatar answered Sep 21 '22 08:09

Jared Farrish