0

I'm writing an application that collects analytics data, and builds up a HTML page with statistics and Google Charts. When that is done, I use snappyBundle to convert the HTML page (with CSS) to a PDF document.

So far, everything has worked fine. Now, I'm creating a class (extending from containerAwareCommand) to ensure that I can run the process from cmd (It has to run on a server every 5 minutes when it goes live).

When I execute the method that converts the HTML into PDF from the webapplication itself, it works fine. But when I run the method from cmd, I keep getting the same error:

 [RuntimeException]
 The exit status code '1' says something went wrong:
 stderr: ""
 stdout: ""
 command: C:\wkhtmltopdf\bin\wkhtmltopdf.exe --lowquality "C:\Users\TARSFR~1\AppData    \Local\Temp\knp_snappy53468b3d5c
 5fe2.34590556.html" "/pdf/11706096/2014/2014-04.pdf".

This is the method that is responsible for generating the PDF:

public function generate1PDF($customer, $cmd)
{
    if (file_exists('/pdf/' . $customer->getGoogleViewID() . '/' . date("Y") . '/' . date("Y-m") . '.pdf')) {
        //PDF already exists. Delete it (because generating a new one will have more recent data)
        unlink('/pdf/' . $customer->getGoogleViewID() . '/' . date("Y") . '/' . date("Y-m") . '.pdf');
    }

    $arr = $this->prepareReport($customer);

    if ($arr instanceof Response) {
        return $arr;
    }

    $data = $arr['data'];
    $report = $arr['report'];

    if ($report !== null) {

        $html = $this->templating->render('itrLoginBundle:Report:report.html.twig', array('report' => $data, 'klant' => $customer, 'rapport' => $report, 'cmd' => null));

            //This is where the error occurs:
            $this->knpSnappy->generateFromHtml($html, '/pdf/' . $customer->getGoogleViewID() . '/' . date("Y") . '/' . date("Y-m") . '.pdf');

        $this->reportRepository->updateGenerated($report);
    }
}

The HTML differs, depending on what kind of analytics data is collected. Here is an example though, for those who think it might be useful (I have cut out some javascript to not exceed the 30k char limit. These methods are responsible for populating & drawing the google charts):

    <html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta name="keywords" content=""/>
    <meta name="description" content=""/>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Klanten Analytics</title>
    <link href='http://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Droid+Serif:400,700italic,700,400italic' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="http://localhost/Symfony/web/css/styleReport.css" type="text/css"/>
        <!--Load the AJAX API-->

    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">I've cut out some javascript methods to not exceed the 30k char limit. These javascript methods are responsible for populating & drawing the google charts</script>
</head>
<body>
<div id="outer">

    <div id="main">
        <div id="content">
            <div id="box1">

                    <table style="text-align: left; padding-bottom: 25px; width: 100%;border-bottom: 1px solid lightgray">
                        <tr>
                            <td class="itrLogo"><img
                                        src="http://localhost/Symfony/web/images/Intracto_logo.jpg"
                                        alt="Intracto logo"/>                                <br/> <br/>

                            </td>
                            <td style="text-align:right;"><h1 id="titelTabel">Uw maandelijkse statistieken van: <a
                                            href="www.intracto.com">www.intracto.com</a></h1>

                                <h2>Rapport 04-2014</h2>

                                <h2 class="periodeRapport">
                                    Periode: 10/03/2014
                                    - 10/04/2014</h2></td>
                        </tr>
                    </table>
                    <br/>
                    <div class="chapter">
                        <h1 class="subTitle">Bezoekers</h1>
<div class="uitleg">Een overzicht van het aantal bezoekers op je website de afgelopen maand vergeleken met het aantal unieke bezoekers. Eenzelfde persoon die meerdere keren bezoekt, wordt in het bezoekersaantal ook iedere keer mee geregistreerd. Bij unieke bezoekers wordt eenzelfde persoon slechts eenmaal geregistreerd.</div>
<br/>
<div class="doelTitel">Huidige maand</div>
<div id="bezoekersHuidigeMaand" class="chart"></div>
<br class="clear">
<div class="doelTitel">Vorige maand</div>
<div id="bezoekersVorigeMaand" class="chart"></div>
                    </div>
                    <hr style="color:#807f7f"/>
                    <div style="text-align:left">Maandelijkse statistieken: <a href="www.intracto.com">www.intracto.com</a><div style="float:right;text-align:right;">Pagina: 1 / 5</div></div>
                                                            <div class="chapter">
                        <h1 class="subTitle">Sitegebruik</h1>
<div class="uitleg">Het gebruik van een website is afhankelijk van de context. Toch kunnen deze algemene gegevens een
    inzicht bieden op mogelijke verbeterpunten.
    Een algemeen bouncepercentage geeft weer hoeveel percent van je bezoekers na het bezoeken van één pagina je site al
    weer verlaat. Algemeen zou dit zo laag mogelijk moeten zijn, maar voor specifieke pagina’s (bijv. een pagina met
    openingsuren) kan dit net omgekeerd zijn.
    Neem <a href="mailto:katrien.sebrechts@intracto.com">contact</a> op met Intracto voor een juiste interpretatie van
    deze gegevens voor jouw site.
</div>
<br/><br/>
<table class="bordered" id="kerncijfersTop">
    <tr>
        <td style="text-align: center;" width="52%"><h1
                    class="cijfer">3,613</h1>

            <div class="grijs">Totale bezoekers</div>
            <div>
                                                    <div class="arrowUp" style="margin-left: 42%">
                        464
                    </div>
                                            </div>
        </td>
    </tr>
    <tr>
        <td class="vorigePeriode">Vorige
            periode: 3,149</td>
    </tr>
</table>
<br class="clear"/><br/>

<div class="kerncijfersTables">
    <table class="bordered" style="width:30%;float:left;margin-right: 5%;">
        <tr>
            <td><h1 class="cijfer">10,365</h1>

                <div class="grijs">Paginaweergaves</div>

                <div style="border-left: 0px;">
                                                                <div class="arrowUp">
                            760
                        </div>
                                                        </div>
            </td>
        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 9,605</td>
        </tr>
    </table>

    <table class="bordered" style="width:30%;float:left;margin-right: 5%">
        <tr>
            <td><h1 class="cijfer">00:01:55</h1>

                <div class="grijs">Gemiddelde tijd op site</div>
                <div style="border-left: 0px;">
                                            <div class="arrowDown">
                        00:00:12
                        </div>                                                        </div>
            </td>

        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 00:02:07</td>
        </tr>
    </table>

    <table class="bordered" style="width:30%;float:left;">
        <tr>
                                    <td><h1 class="cijfer">2.87</h1>

                <div class="grijs">Pagina's per bezoek</div>
                <div style="border-left: 0px;">
                                            <div class="arrowDown">
                            -0.18
                        </div>
                                                                            </div>
            </td>

        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 3.05</td>
        </tr>
    </table>
</div>
<br class="clear"/>
<div class="kerncijfersTables">
    <table class="bordered" style="width:30%;float:left;margin-right: 5%;">
        <tr>
                                    <td><h1 class="cijfer">69.53
                    %</h1>

                <div class="grijs">Nieuwe bezoeken</div>

                <div style="border-left: 0px;">
                                            <div class="arrowDown">
                        -0.11
                        %
                        </div>                                                        </div>
            </td>
        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 69.64%
            </td>
        </tr>
    </table>

    <table class="bordered" style="width:30%;float:left;margin-right: 5%">
        <tr>
                                    <td><h1 class="cijfer">51.76%</h1>

                <div class="grijs">Bouncepercentage</div>

                <div style="border-left: 0px;">
                                                                <div class="arrowUp">
                            +0.09%
                        </div>
                                                        </div>
            </td>
        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 51.67%
            </td>
        </tr>
    </table>

    <table class="bordered" style="width:30%;float:left;">
        <tr>
            <td><h1 class="cijfer">2,763</h1>

                <div class="grijs">Unieke bezoekers</div>

                <div style="border-left: 0px;">
                                                                <div class="arrowUp">
                        +328
                        </div>                                    </div>
            </td>
        </tr>
        <tr>
            <td class="vorigePeriode">Vorige
                periode: 2,435</td>
        </tr>
    </table>
</div>
<br class="clear"/>
                    </div>
                    <br class="clear"/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
                    <hr style="color:#807f7f"/>
                    <div style="text-align:left">Maandelijkse statistieken: <a href="www.intracto.com">www.intracto.com</a><div style="float:right;text-align:right;">Pagina: 2 / 5</div></div>
                                                            <div class="chapter">
                        <h1 class="subTitle">Top 5 landen</h1>
<div class="uitleg">Een overzicht van de landen van waaruit de bezoekers van je website surfen. Dit kan belangrijke informatie zijn om internationale interesse voor je merk te peilen.</div>
<br/>
<div class="doelTitel">Belangrijkste landen</div>
<div id="piechart" class="chart"></div>
<br class="clear"/><br/><br/>
<div class="doelTitel">Wereldkaart ingekleurd naar bezoekersaantal</div>
<div id="kaartLanden" class="chart"></div>
<br class="clear">
<br/>                    </div>
                    <br class="clear"/><br/><br/><br/><br/>
                    <hr style="color:#807f7f"/>
                    <div style="text-align:left">Maandelijkse statistieken: <a href="www.intracto.com">www.intracto.com</a><div style="float:right;text-align:right;">Pagina: 3 / 5</div></div>
                                                            <div class="chapter">
                        <h1 class="subTitle">Top 10 verkeersbronnen</h1>
<div class="uitleg">Hoe komen bezoekers op jouw website terecht? Deze lijst geeft bijv. een antwoord of die inspanningen op social media zijn vruchten heeft afgeworpen? Of er voldoende bezoekers via zoekresultaten van Google binnen komen?</div>
<br/>
<div class="doelTitel">Belangrijkste verkeersbronnen</div>
<div id="verkeersbronBar" class="chart"></div>
                    </div>
                    <div class="chapter">
                        <h1 class="subTitle">Mobiel gebruik</h1>
<div class="uitleg">Het internetverkeer verloopt meer en meer via mobiele apparaten, zoals tablets en smartphones. Een stijgend percentage kan reden zijn om je website mobiel te optimaliseren om ook dat publiek voldoende te bereiken. Zeker als dit gekoppeld is met een hoog bouncepercentage.</div>
<br/>
<div class="doelTitel">Mobiel gebruik</div>
<div id="mobielPieChart" class="chart"></div>
                    </div>
                    <br class="clear"/>
                    <hr style="color:#807f7f"/>
                    <div style="text-align:left">Maandelijkse statistieken: <a href="www.intracto.com">www.intracto.com</a><div style="float:right;text-align:right;">Pagina: 4 / 5</div></div>
                                                            <div class="chapter">
                        <h1 class="subTitle">Top 25 pagina's</h1>
<div class="uitleg">Dit overzicht van de best bezochte pagina’s geeft een beeld van welke inhoud het beste scoort. Richt zeker je aandacht op pagina’s die rechtstreeks gekoppeld zijn aan conversies.</div>
<br />
<div class="doelTitel">Belangrijkste pagina's</div>
<div id="paginasBarChart" class="chart"></div>                    </div>

                    <br class="clear"/>
                    <br/><br/><br /><br/><br/><br/><br/><br/><br/>
                    <hr style="color:#807f7f"/>
                    <div style="text-align:left">Maandelijkse statistieken: <a href="www.intracto.com">www.intracto.com</a><div style="float:right;text-align:right;">Pagina: 5 / 5</div></div>




            </div>

            <br class="clear"/>
        </div>

        <br class="clear"/>
    </div>

</div>

<div id="copyright">
    &copy; Intracto digital agency | maandelijks rapport Google Analytics
</div>

<div id="sfwdtca70aa" class="sf-toolbar" style="display: none"></div><script>/*<![CDATA[*/    Sfjs = (function() {        "use strict";        var noop = function() {},            profilerStorageKey = 'sf2/profiler/',            request = function(url, onSuccess, onError, payload, options) {                var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');                options = options || {};                xhr.open(options.method || 'GET', url, true);                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');                xhr.onreadystatechange = function(state) {                    if (4 === xhr.readyState && 200 === xhr.status) {                        (onSuccess || noop)(xhr);                    } else if (4 === xhr.readyState && xhr.status != 200) {                        (onError || noop)(xhr);                    }                };                xhr.send(payload || '');            },            hasClass = function(el, klass) {                return el.className.match(new RegExp('\\b' + klass + '\\b'));            },            removeClass = function(el, klass) {                el.className = el.className.replace(new RegExp('\\b' + klass + '\\b'), ' ');            },            addClass = function(el, klass) {                if (!hasClass(el, klass)) { el.className += " " + klass; }            },            getPreference = function(name) {                if (!window.localStorage) {                    return null;                }                return localStorage.getItem(profilerStorageKey + name);            },            setPreference = function(name, value) {                if (!window.localStorage) {                    return null;                }                localStorage.setItem(profilerStorageKey + name, value);            };        return {            hasClass: hasClass,            removeClass: removeClass,            addClass: addClass,            getPreference: getPreference,            setPreference: setPreference,            request: request,            load: function(selector, url, onSuccess, onError, options) {                var el = document.getElementById(selector);                if (el && el.getAttribute('data-sfurl') !== url) {                    request(                        url,                        function(xhr) {                            el.innerHTML = xhr.responseText;                            el.setAttribute('data-sfurl', url);                            removeClass(el, 'loading');                            (onSuccess || noop)(xhr, el);                        },                        function(xhr) { (onError || noop)(xhr, el); },                        options                    );                }                return this;            },            toggle: function(selector, elOn, elOff) {                var i,                    style,                    tmp = elOn.style.display,                    el = document.getElementById(selector);                elOn.style.display = elOff.style.display;                elOff.style.display = tmp;                if (el) {                    el.style.display = 'none' === tmp ? 'none' : 'block';                }                return this;            }        }    })();/*]]>*/</script><script>/*<![CDATA[*/    (function () {                Sfjs.load(            'sfwdtca70aa',            '/Symfony/web/app_dev.php/_wdt/ca70aa',            function(xhr, el) {                el.style.display = -1 !== xhr.responseText.indexOf('sf-toolbarreset') ? 'block' : 'none';                if (el.style.display == 'none') {                    return;                }                if (Sfjs.getPreference('toolbar/displayState') == 'none') {                    document.getElementById('sfToolbarMainContent-ca70aa').style.display = 'none';                    document.getElementById('sfToolbarClearer-ca70aa').style.display = 'none';                    document.getElementById('sfMiniToolbar-ca70aa').style.display = 'block';                } else {                    document.getElementById('sfToolbarMainContent-ca70aa').style.display = 'block';                    document.getElementById('sfToolbarClearer-ca70aa').style.display = 'block';                    document.getElementById('sfMiniToolbar-ca70aa').style.display = 'none';                }            },            function(xhr) {                if (xhr.status !== 0) {                    confirm('An error occurred while loading the web debug toolbar (' + xhr.status + ': ' + xhr.statusText + ').\n\nDo you want to open the profiler?') && (window.location = '/Symfony/web/app_dev.php/_profiler/ca70aa');                }            }        );    })();/*]]>*/</script>
</body>
</html>
Tars
  • 1
  • 2
  • The executed `wkhtmltopdf` command tries to generate an absolute unix-style path: "/pdf/11706096/2014/2014-04.pdf". Your question lacks information that would enable us to further debug the cause. If you plan to deploy to a unix system ... i strongly recommend you to develop/test on a unix system instead of using windows-versions of i.e. `wkhtmltopdf`. (vmware/virtualbox/vagrant/veewee/packer/chef/puppet/ansible ... to throw in a few keywords) – Nicolai Fröhlich Apr 10 '14 at 13:30
  • @nifr Could you specify what additional information you need? I'd be happy to post all the information I can give you. I can understand that the command indeed tries to generate an absolute unix-style path, but I don't understand why that would make it work, when executed from the webapplication itself, but not when executed form cmd. Could you explain in further detail? (I'm quite new to symfony2: ~7weeks of experience now). The application is indeed intented to deploy on a unix system. I will be testing/debugging on unix later on, thank you for the tip. – Tars Apr 10 '14 at 13:57

0 Answers0