我正在编写一个收集分析数据的应用程序,并使用统计数据和 Google 图表构建一个 HTML 页面。完成后,我使用 snappyBundle 将 HTML 页面(使用 CSS)转换为 PDF 文档。
到目前为止,一切正常。现在,我正在创建一个类(从 containerAwareCommand 扩展)以确保我可以从 cmd 运行该进程(它必须每 5 分钟在服务器上运行一次)。
当我执行从 web 应用程序本身将 HTML 转换为 PDF 的方法时,它工作正常。但是当我从 cmd 运行该方法时,我不断收到相同的错误:
[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".
这是负责生成 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);
}
}
HTML 会有所不同,具体取决于收集的分析数据类型。不过,对于那些认为它可能有用的人来说,这是一个示例(我已经删除了一些 javascript 以不超过 30k 字符的限制。这些方法负责填充和绘制谷歌图表):
<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">
© 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>