Creating PDF files with Html2ps/Html2pdf

This article is also available in the following languages:
By Casmo
Html2ps (also known as Html2pdf) is a free PHP tool wich allows users to create their own PDF files from a complete designed html page. The different between this version and the one from Kalileo (http://bakery.cakephp.org/articles/view/creating-pdf-files-with-cakephp-and-tcpdf) is that this Html2pdf allows complete websites including all css files, images, tables, divs, etc.

Requirements


Step 1: Download and install Html2ps

  1. Go to http://www.tufat.com/s_html2ps_html2pdf.htm and download the latest version of Html2ps.
  2. Unzip the files to the vendor map /app/vendors/html2ps/.
  3. Open pipeline.class.php and search for "$this->_dispatcher =& new Dispatcher();" and replace it with: "$this->_dispatcher =& new DispatcherPdf();".
  4. Open dispatcher.class.php and change to following lines: "class Dispatcher {" into "class DispatcherPdf {" and "function Dispatcher() {" into "function DispatcherPdf() {".

Step 2: The Pdf Component

Make a file pdf.php in /app/controllers/components and paste the following code.

Component Class:

<?php 
class PdfComponent extends Object {

    var 
$p;                         // The Pdf Class
    
var $media;
    var 
$filename 'invoice';    // Without the .pdf
    
var $output 'browser';      // browser,file,download

  
function init() {

      
// Include the class file and create Html2ps instance
      
App::import('vendor''Html2PsConfig', array('file' => 'html2ps'.DS.'config.inc.php'));
      
App::import('vendor''Html2Ps', array('file' => 'html2ps'.DS.'pipeline.factory.class.php'));
      
parse_config_file(APP .'vendors'DS .'html2ps'DS .'html2ps.config');

      global 
$g_config;
      
$g_config = array(
                
'cssmedia'     => 'screen',
                
'renderimages' => true,
                
'renderforms'  => false,
                
'renderlinks'  => true,
                
'mode'         => 'html',
                
'debugbox'     => false,
                
'draw_page_border' => false
                
);

    
$this->media Media::predefined('A4');
    
$this->media->set_landscape(false);
    
$this->media->set_margins(array('left'   => 0,
                              
'right'  => 0,
                              
'top'    => 0,
                              
'bottom' => 0));
    
$this->media->set_pixels(1024);
    global 
$g_px_scale;
    
$g_px_scale mm2pt($this->media->width() - $this->media->margins['left'] - $this->media->margins['right']) / $this->media->pixels;
    global 
$g_pt_scale;
    
$g_pt_scale $g_pt_scale 1.43;
    
$this->PipelineFactory::create_default_pipeline("","");

    switch (
$this->output) {
      case 
'download':
      
$this->p->destination = new DestinationDownload($this->filename);
      break;
      case 
'file':
      
$this->p->destination = new DestinationFile($this->filename);
      break;
      default:
      
$this->p->destination = new DestinationBrowser($this->filename);
      break;
    }
    
  }

  function 
process($url) {
    
$this->p->process($url$this->media);
  }
}
?>
The above code is a very basic setup for Html2ps. You can change whatever you want to fit your PDF requirements.

Step 3: The Pdf layout

We will use a different layout for the Pdf files then the default.ctp. With this we are able to have a different layout then the website itself. Create the file pdf.ctp in /app/views/layout/ and paste the following code.

View Template:


<?php echo $content_for_layout?>
You're free to use any css files or images you like. In this example we only use a white paper for the layout.

Step 4: The Controller functions

The rendering of the Pdf files happens in a controller function. In this example I use the "Invoices" controller with two functions: view() and download(). The view() displays the normal html file and the download() renders the view in PDF format.
Paste the following functions in your controller.

Controller Class:

<?php 
class InvoicesController extends AppController {

    var 
$name 'Invoices';

    function 
view($id null) {
        
// Be sure that the current user can download this Invoice...
        
$this->set('invoiceNumber''1234');
    }

    function 
download($id null) {
        
// Include Component
        
App::import('Component''Pdf');
        
// Make instance
        
$Pdf = new PdfComponent();
        
// Invoice name (output name)
        
$Pdf->filename 'your_invoice'// Without .pdf
        // You can use download or browser here
        
$Pdf->output 'download';
        
$Pdf->init();
        
// Render the view
        
$Pdf->process(Router::url('/'true) . 'invoices/view/'$id);
        
$this->render(false);
    }
}
?>

Step 5: That's it!

Make a nice view of your invoice in /app/views/invoices/view.ctp and open http://www.fellicht.nl/invoices/download/1234.

If you have any questions, suggestions or mistakes in the above article please submit them!

Comments

  • Posted 07/28/11 09:23:29 PM
    my css is not working, its print my page ok, but without my css, can any1 help me?
  • Posted 07/16/11 05:42:39 PM
    When i send the function invoices, sendme only words in server Centos, but in local with ubuntu sendme download file, i need hel plis ;D
  • Posted 04/29/11 03:46:43 AM
    Hi!

    This works perfectly in my computer, but when I test it online it doesn't work. It seems don't recognize any php code.
    What could be the problem here?

    Thank you!!!
    Jorge
  • Posted 03/30/11 11:53:25 PM
    I'm having this problem: Cannot redeclare class file in (...)/vendors/html2ps/classes/org/active-link/sys/File.php on line 0

    Locally, it works fine, but once in the server it doesn't. I tried the other solution below but they didn't work.

    Please, help.
    • Posted 04/08/11 12:50:16 AM
      [quote] I'm having this problem: Cannot redeclare class file in (...)/vendors/html2ps/classes/org/active-link/sys/File.php on line 0

      Locally, it works fine, but once in the server it doesn't. I tried the other solution below but they didn't work.

      Please, help.
      [end quote]
      By the way, it works on mi computer (with XAMPP) but not in the server.
  • Posted 03/30/11 01:26:00 PM
    It creates the pdf file but it just seems as if it has kept pdf extension. The file created is not opened by the pdf reader. It gives error "Acrobat could not open 'your_report.pdf' because it is either not a supported file type or because the file has been damaged'.

    Need help about it
  • Posted 03/03/11 05:26:45 AM
    [quote] [quote] Fatal Error (256): pcre.pcre.backtrack_limit(100000) and pcre.recursion_limit(100000) too low [APP\vendors\html2ps\xhtml.utils.inc.php, line 51] Code | Context
    [end quote]
    hi! were you able to find a solution for this? i'm getting same error while trying to create a pdf w/ images and more than 1 table.

    i tried to change backtrack_limit and recursion_limit in php.ini but it doesnt seem to take effect in my cakephp app.

    i wish someone could post a solution for this. thanks in advance!
    [end quote]
    updating my post.. i was able to allow my cakephp app to convert html to pdf and download it successfully now.
    what i did to correct the fatal error 256 is that i changed the values of backtrack_limit and recursion_limit to 1000000. when i thought it wasnt taking effect in my app, i figured it was because the default line for backtrack and recursion was commented out. so i removed the ';' before the 2 lines, changed the values, saved the php.ini and then restart my wamp.
    but then i encountered another error about bytes exhausted. while looking for answers i found a solution in this site http://ask.cakephp.org/questions/view/fatal_error_allowed_memory_size_of_25165824_bytes_exhausted_tried_to_allocate_29_bytes and applied it in my app. after that my download for pdf worked.
    maybe this post could help someone who has same problem.
    just that i noticed my app is taking time to show the download window. i dunno if there's a way to make it faster. continuing my adventure on this coz this is my first time creating a web app and first time using cakephp.
  • Posted 02/23/11 01:44:26 AM
    hi,
    the pdf file thas generated from class is not opened. i have get the message when i try to open pdf:
    "Adobe reader could open "invoice12.pdf" because it is either not a support file type or because the file has been damaged (for example, it was sent as email attachment and was'nt correctly decoded).
    hope u wil find solution for me!
    thanks,
    • Posted 02/26/11 02:02:33 PM
      [quote] hi,
      the pdf file thas generated from class is not opened. i have get the message when i try to open pdf:
      "Adobe reader could open "invoice12.pdf" because it is either not a support file type or because the file has been damaged (for example, it was sent as email attachment and was'nt correctly decoded).
      hope u wil find solution for me!
      thanks,

      [end quote]
    • Posted 02/26/11 02:01:37 PM
      [quote] hi,
      the pdf file thas generated from class is not opened. i have get the message when i try to open pdf:
      "Adobe reader could open "invoice12.pdf" because it is either not a support file type or because the file has been damaged (for example, it was sent as email attachment and was'nt correctly decoded).
      hope u wil find solution for me!
      thanks,

      [end quote]
  • Posted 02/14/11 04:19:14 PM
    im using cakephp 1.37

    and i m getting this error

    Fatal error: Class 'Media' not found in C:\wamp\www\age\app\controllers\components\pdf.php on line 28

    pls i need help.

    thx anyway
  • Posted 02/11/11 10:33:18 AM
    Hi, I'm getting this error with an html file larger than others (2 charts generated and saved by the controller before the view with a lot of tables, with one chart it works) :

    Fatal Error (256): pcre.pcre.backtrack_limit(100000) and pcre.recursion_limit(100000) too low [APP\vendors\html2ps\xhtml.utils.inc.php, line 51] Code | Context



    if (!$html) {

    trigger_error('pcre.pcre.backtrack_limit('.ini_get('pcre.backtrack_limit').') and pcre.recursion_limit('.ini_get('pcre.recursion_limit').') too low', E_USER_ERROR);

    $html = ""
    $open = "]*)?>"
    $close = ""

    process_html - APP\vendors\html2ps\xhtml.utils.inc.php, line 51
    html2xhtml - APP\vendors\html2ps\xhtml.utils.inc.php, line 415
    DataFilterHTML2XHTML::process() - APP\vendors\html2ps\filter.data.html2xhtml.class.php, line 9
    Pipeline::_layout_item() - APP\vendors\html2ps\pipeline.class.php, line 1144
    Pipeline::_process_item() - APP\vendors\html2ps\pipeline.class.php, line 789
    Pipeline::process_batch() - APP\vendors\html2ps\pipeline.class.php, line 997
    Pipeline::process() - APP\vendors\html2ps\pipeline.class.php, line 957
    PdfComponent::process() - APP\controllers\components\pdf.php, line 56
    MyController::download() - APP\controllers\my_controller.php, line 696
    Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 204
    Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 171
    [main] - APP\webroot\index.php, line 84

    It takes time to generate the pdf and i see in my chart image folder that two images are generated, so the page is load two times ???
    • Posted 03/03/11 04:05:19 AM
      [quote] Fatal Error (256): pcre.pcre.backtrack_limit(100000) and pcre.recursion_limit(100000) too low [APP\vendors\html2ps\xhtml.utils.inc.php, line 51] Code | Context
      [end quote]
      hi! were you able to find a solution for this? i'm getting same error while trying to create a pdf w/ images and more than 1 table.

      i tried to change backtrack_limit and recursion_limit in php.ini but it doesnt seem to take effect in my cakephp app.

      i wish someone could post a solution for this. thanks in advance!
  • VdC
    Posted 01/26/11 03:10:31 AM
    Hi,

    when i test this component in localhost all is good, but when i upload on 1&1 my pdf generate is empty, and there is no error report.

    i hope you will have any solution.
  • Posted 12/01/10 02:29:24 PM
    How would you go about printing batch pdfs?
  • Posted 12/01/10 04:15:56 AM
    Im getting the following error:
    Warning (512): SQL Error: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'copy' at line 1 [CORE/cake/libs/model/datasources/dbo_source.php, line 681] Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Query: copy

    Any suggestions?
  • Posted 11/29/10 07:52:38 PM
    Hi, thank's for your "how to", it's works perfectly for me, but i have one problem...

    I have this in my view.ctp



    so, when the browser download the asociate pdf of this view, the Session array it's empty...
    I print the view in other window, and show me the Session array correctly

    I need to configure something more????

    Best regards...

    Gustavo Delgado R.
    • Posted 11/29/10 07:56:47 PM
      [quote] Hi, thank's for your "how to", it's works perfectly for me, but i have one problem...

      I have this in my view.ctp

      print_r($_SESSION);

      so, when the browser download the asociate pdf of this view, the Session array it's empty and show me this...

      Array ( [Config] => Array ( [userAgent] => [time] => 1291094594 [timeout] => 10 ) )

      I print the view in other window, and show me the Session array correctly

      I need to configure something more????

      Best regards...

      Gustavo Delgado R.
      [end quote]
  • Posted 11/21/10 10:22:51 AM
    Warning (512): Cannot open http://localhost:8080/BarcodePortal/departures/deliverynotepdf/1 [APP\vendors\html2ps\fetcher.url.class.php, line 94] Code | Context



    trigger_error(sprintf("Cannot open %s",

    $data_id), E_USER_WARNING);

    $data_id = "http://localhost:8080/BarcodePortal/departures/deliverynotepdf/1"
    $_server_response = null
    $_url = "http://localhost:8080/BarcodePortal/departures/deliverynotepdf/1"

    FetcherUrl::get_data() - APP\vendors\html2ps\fetcher.url.class.php, line 94
    Pipeline::fetch() - APP\vendors\html2ps\pipeline.class.php, line 941
    Pipeline::_layout_item() - APP\vendors\html2ps\pipeline.class.php, line 1137
    Pipeline::_process_item() - APP\vendors\html2ps\pipeline.class.php, line 790
    Pipeline::process_batch() - APP\vendors\html2ps\pipeline.class.php, line 998
    Pipeline::process() - APP\vendors\html2ps\pipeline.class.php, line 958
    PdfComponent::process() - APP\controllers\components\pdf.php, line 55
    DeparturesController::deliverynotepdf() - APP\controllers\departures_controller.php, line 48
    Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 204
    Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 171
    [main] - APP\webroot\index.php, line 83


    I need some help. Thanks in advance
  • Posted 11/17/10 05:43:02 PM
    I'm unable to render images when running from the either the Cake shell or even running one of the sample scripts from the CLI? Images are absolutely referenced, but I haven't overridden the default Fetcher get_base_url() function (yet). Any pointers?

    Thanks
  • Posted 11/04/10 02:07:56 PM
    Warning (2): Cannot modify header information - headers already sent by (output started at D:\Localhost\simpel\app\controllers\components\pdf.php:58) [APP\vendors\html2ps\destination._http.class.php, line 12]

    I solve this problem with removing ?> on line 58 from pdf.php component
  • Posted 11/03/10 08:06:44 AM
    Hi There,

    Thanks for the greate helper, but PDF that the class is generating is not opening. I get the following error from Adobe Reader: "Adobe reader could open "invoice12.pdf" because it is either not a support file type or because the file has been damaged (for example, it was sent as email attachment and was'nt correctly decoded).

    I have checked html2pdf website, but cannot find anything useful.

    Thanks for your help

    Sudhir

  • Posted 08/30/10 03:57:48 AM
    I'm trying to create an action to app_controller to enable creation of pdf file from any controller/action. It is not possible to allow all actions because it would just eliminate the use of acl and auth in general.

    Is there a way to give the pdf-component temporary rights, change it to act as user with it's rights or create aro for the pdf-component so it would have rights in the acl-database?
  • Posted 08/26/10 09:55:06 AM
    I'm working with cakephp 1.2 and i follwed all the instructions. However, i always get an error at processiong the pdf file. The error says something about 'file corrupted'. Any ideas?

    Thanks by the way.
  • Posted 08/10/10 07:48:05 AM
    Well, near to working
    I have an error like this :

    $tmp_filename = "E:\xampp\htdocs\gestion\app\vendors\html2ps\temp\PS_143.tmp"
    $content_type = ContentType
    ContentType::$default_extension = "pdf"
    ContentType::$mime_type = "application/pdf"header - [internal], line ??
    DestinationHTTP::process() - APP\vendors\html2ps\destination._http.class.php, line 12
    Pipeline::_output() - APP\vendors\html2ps\pipeline.class.php, line 915
    Pipeline::close() - APP\vendors\html2ps\pipeline.class.php, line 366
    Pipeline::process_batch() - APP\vendors\html2ps\pipeline.class.php, line 1003
    Pipeline::process() - APP\vendors\html2ps\pipeline.class.php, line 957
    PdfComponent::process() - APP\controllers\components\pdf.php, line 55
    OperationController::telecharger() - APP\controllers\operation_controller.php, line 243
    Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 204
    Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 171
    [main] - APP\webroot\index.php, line 83

    Thanks for your help.
    regards.
  • Posted 08/09/10 12:43:44 PM
    I was having the same problem as David. I was making a PDF of Auth protected content.

    I finally had to put a beforeFilter in my controller:

    function beforeFilter()
    {
    $this->Auth->allow('download','view');
    parent::beforeFilter();
    }

    I have to explicitly autorize both the download and the view actions. After doing this, it no longer gave me a PDF of my login page.

    Hope this helps someone...
  • Posted 07/26/10 03:00:15 PM
    Getting this error when following your tutorial:

    Fatal error: Cannot redeclare class File in /app/vendors/html2ps/classes/org/active-link/sys/File.php on line 33
    • Posted 08/06/10 10:45:50 AM
      Getting this error when following your tutorial:

      Fatal error: Cannot redeclare class File in /app/vendors/html2ps/classes/org/active-link/sys/File.php on line 33

      You can try to edit the file "/app/vendors/html2ps/classes/org/active-link/sys/File.php" and replace the following lines:

      class File {
      into
      class FilePdf {
      and

      function File($filename = "", $fileOpenMode = "r") {
      into
      function FilePdf($filename = "", $fileOpenMode = "r") {

      I don't know where this class is used but if you get an error according File class not found you should search for the file/linenumber of the error and replace the classname "File" into "FilePdf".
    • Posted 07/27/10 11:02:29 PM
      Getting this error when following your tutorial:

      Fatal error: Cannot redeclare class File in /app/vendors/html2ps/classes/org/active-link/sys/File.php on line 33

      I got similar problem when i first run the test. It said:

      Fatal error: Cannot redeclare class Destination in .....

      Eventually there is a model class called Destination in my app. I give a try to rename my class.. my problem solved.

      So, not sure you are having same situation where u got the File class somewhere. Hope this could help.
  • Posted 07/21/10 08:57:21 PM
    I got this warning when tried to download a PDF. It seems the code tried to echo something to the screen before the PDF created.
    Did I miss something in my setup? I have followed the steps explained.

    Warning (2): Cannot modify header information - headers already sent by (output started at D:\Localhost\simpel\app\controllers\components\pdf.php:58) [APP\vendors\html2ps\destination._http.class.php, line 12] Code | Context

    $tmp_filename = "D:\Localhost\simpel\app\vendors\html2ps\temp\PS_AF4.tmp"
    $content_type = ContentType
    ContentType::$default_extension = "pdf"
    ContentType::$mime_type = "application/pdf"

    header - [internal], line ??
    DestinationHTTP::process() - APP\vendors\html2ps\destination._http.class.php, line 12
    Pipeline::_output() - APP\vendors\html2ps\pipeline.class.php, line 915
    Pipeline::close() - APP\vendors\html2ps\pipeline.class.php, line 366
    Pipeline::process_batch() - APP\vendors\html2ps\pipeline.class.php, line 1003
    Pipeline::process() - APP\vendors\html2ps\pipeline.class.php, line 957
    PdfComponent::process() - APP\controllers\components\pdf.php, line 55
    RegistrationsController::download() - APP\controllers\registrations_controller.php, line 22
    Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 204
    Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 171
    [main] - APP\webroot\index.php, line 83

    Thanks in advance.
    • Posted 08/06/10 10:52:08 AM
      I got this warning when tried to download a PDF. It seems the code tried to echo something to the screen before the PDF created.
      Did I miss something in my setup? I have followed the steps explained.

      Thanks in advance.

      I'm not sure but maybe the Pdf component is producing a notice error or something like that. If not, you should be sure that you have a give a correct $url parameter in the process function.

      $Pdf->process($url_to_html_page); // This is probably in your controller
  • Posted 07/08/10 11:36:09 AM
    Try to include in the step 4, below the line:

    function view($id = null) {
    // It will call the PDF layout
    $this->layout = 'pdf';
  • Posted 07/01/10 07:20:47 AM
    I have a problem when i want to generate a pdf i have the error :

    Fatal error: Call to undefined function parse_config_file() in /home/...../app/controllers/components/pdf.php on line 14

    I'm using CakePHP 1.3
    • Posted 07/01/10 01:52:56 PM
      I have a problem when i want to generate a pdf i have the error :

      Fatal error: Call to undefined function parse_config_file() in /home/...../app/controllers/components/pdf.php on line 14

      I'm using CakePHP 1.3

      Did you place the html2pdf in the correct directory?
      /app/vendors/html2ps/

      Be sure that the component can include the required files. See this two lines:
            App::import('vendor', 'Html2PsConfig', array('file' => 'html2ps'.DS.'config.inc.php'));
            App::import('vendor', 'Html2Ps', array('file' => 'html2ps'.DS.'pipeline.factory.class.php'));
      • Posted 07/02/10 03:37:13 AM
        My problem was due to read or write permissions. After a chmod 777 -R on the html2ps folder everything work.

        I have a problem when i want to generate a pdf i have the error :

        Fatal error: Call to undefined function parse_config_file() in /home/...../app/controllers/components/pdf.php on line 14

        I'm using CakePHP 1.3

        Did you place the html2pdf in the correct directory?
        /app/vendors/html2ps/

        Be sure that the component can include the required files. See this two lines:
              App::import('vendor', 'Html2PsConfig', array('file' => 'html2ps'.DS.'config.inc.php'));
              App::import('vendor', 'Html2Ps', array('file' => 'html2ps'.DS.'pipeline.factory.class.php'));
  • Posted 06/29/10 09:35:29 AM
    I am trying to generate pdfs off of auth/acl protected content. Instead of getting the desired page as a pdf I am getting a pdf of my login page. Is there something I am missing as to how to give the component the same access as the current user?

    Putting this into beforefilter makes it work:

      parent::beforeFilter(); 
      $this->Auth->allow('*');
    However if i try to limit the access just to the one action, it does not:

    if ($this->action == 'download'){
      parent::beforeFilter(); 
      $this->Auth->allow('*');
    }

    Running this on 1.2.5 and it works other then the Auth/Acl issue.
    • Posted 07/01/10 04:23:40 AM
      I am trying to generate pdfs off of auth/acl protected content. Instead of getting the desired page as a pdf I am getting a pdf of my login page. Is there something I am missing as to how to give the component the same access as the current user?
      I'm not sure why it isn't working but you can try the following:
      beforeFilter():
      $this->Auth->allow('download'); And do the check in your view() function. e.g.:
      function view($invoice_id = null, $security_hash = null) {
          $someInvoice = $this->Invoice->find('first', array('conditions' => array('Invoice.id' => $invoice_id, 'Invoice.checksum' => $security_hash)));
      }
      You can set the security hash in your download() function with $this->Invoice->save();.
  • Posted 06/28/10 02:25:11 AM
    Ran this a few times, then got:
    Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 1400 bytes
    • Posted 06/29/10 02:31:01 AM
      Ran this a few times, then got:
      Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 1400 bytes

      I got the same error, asked my host to increase the memory limit and now works near perfectly.

      The only thing I can't work out (which I suspect is a Html2ps/Html2pdf problem) is whenever I close a PDF created by my site I get asked if I want to save changes. I haven't made any changes (just opened it) so I don't know why that's happening. Or indeed if its happening to anyone else?

      Other than that, works great!
      • Posted 07/01/10 03:03:01 AM
        The only thing I can't work out (which I suspect is a Html2ps/Html2pdf problem) is whenever I close a PDF created by my site I get asked if I want to save changes. I haven't made any changes (just opened it) so I don't know why that's happening. Or indeed if its happening to anyone else?
        I don't think to problem is with Html2pdf but with your PDF Reader. Can you try change this code:
        $Pdf->output = 'download'; Into this:
        $Pdf->output = 'browser';

Comments are closed for articles over a year old