1

Bonjour à tous,

J'utilise html2pdf pour un client qui m'impose l'hébergement sous IIS (personne n'est parfait !).

Voici le déroulement (simplifié) de la génération PDF (avec bien sûr HTML2PDF) :
1- chargement de templates HTML
2- remplacement à la volée de données dynamiques
3- génération PDF dans un fichier
4- envoi email avec PDF en PJ
5- redirection du PDF vers le navigateur

Les 4 premières étapes se déroulent bien mais en 5 (sauf à de rares exceptions).
À la place du PDF, j'obtiens le message : "An internal server error occurred. Please try again later."
Si je rafraichis la page, le PDF s'affiche normalement.
Le temps d'exécution n'excède pas 15s.
Par contre, la charge CPU est à 100% tout le temps de l'exécution.
Je crois donc que le script over-flood le serveur !!

y a-t-il une solution ?

Votre avis m'intéresse ! ;-)
--
Ben

2

afin de connaitre exactement le temps d'exécution de chacune des taches, utilise cette fonction

    function getTimerAction()
    {
      global $TIMER_ACTION_LAST;

      list($usec, $sec) = explode(" ", microtime());
      $time = (float)$sec + (float)$usec; 

      $txt = ($TIMER_ACTION_LAST ? "Durée : ".number_format($time-$TIMER_ACTION_LAST, 3, '.', '').'s' : 'Première appel au Timer');
      $TIMER_ACTION_LAST = $time;

      return $txt."\n";
    }


echo "Initialisation : ".getTimerAction();
/// etape 1
echo "Fin etape 1 : ".getTimerAction();
/// etape 2
echo "Fin etape 2 : ".getTimerAction();
/// etape 3
echo "Fin etape 3 : ".getTimerAction();
/// etape 4
echo "Fin etape 4 : ".getTimerAction();
/// etape 5
echo "Fin etape 5 : ".getTimerAction();


comme ca on verra ce qui prend le plus de charge, mais je suis sur que c'est l'étape 3... Car si ton document HTML à convertir en PDF est assez lourd, ca doit venir de là.

En effet, "An internal server error occurred. Please try again later." est souvent associé à un manque de mémoire pour PHP, hors html2pdf peut prendre beaucoup de mémoire au delà de 4 tableaux imbriqués...
Ancien pseudo : lolo

3

merci de ta réponse..
mais ça ne donne rien, pas de message.. toujours le même message même si je supprime la redirection en fin de script !!

4

et si tu enlève l'etape 5 ? et que tu augmentes la mémoire autorisée à PHP ?
Ancien pseudo : lolo

5

j'ai déjà enlevé l'étape 5..

quant à la mémoire dans php.ini: memory_limit = 128M
Suffisant il me semble, au delà ne serait pas raisonnable !

Merci pour ton aide

6

idée toute bête..

Si je remplace les styles imbriqués du type ".table5 td table td" par des style nominatifs ex. ".table5-table",
est-ce que cela aura un impact significatif ?

Je préfère demander car la démarche est somme toute plus laborieuse et longue !

Merci !

7

128Mo ???? woaw c'est énorme ! je dépasse rarement les 32Mo (et encore, c'est quand j'utilise Symfony, généralement je suis à 8Mo

tu doit avoir un pb quelque part...

pour le coup des styles nominatifs, normalement ce n'est pas ca qui prend le plus de ressource, mais bien les tableaux et divs imbriquées

tu pourrais poster ton document HTML ici ? (en enlevant tout ce qui est confidentiel bien sur)

combien de page fait ton PDF ?

as-tu essayé de voir, en mettant que l'étape 1, puis la 1 et la 2, puis la 1 et la 2 et la 3, ... combient prennait chaque etape, et à quel moment ca plantait ?

si le pb vient du nombre de page, tu peux décomposer la convertion en plusieurs fois, en decoupant ton document par pages, et en les incluant en faisant à chaque fois un appel à writeHTML
Ancien pseudo : lolo

8

Update: J'ai supprimé les sources.. trop lourd et le problème ne venant pas de là, elles n'ont pas d'intérêt !

oui je sais.. c'est énorme.. et justement fait pour passer tout en dév... normalement hein ;-)

Tout se passe super vite avant l'étape de génération PDF (étape 3) <1s !
et puis après, plus rien :-(
ça plante à ce moment là..

le document fait 6 pages mais pas toujours pleines !
il y a pas mal de tableaux... certes..

voilà pour un exemple de ce que j'envoi au générateur PDF (cmd > $html2pdf->WriteHTML($content); )

(supprimé!)

il manque le CSS:

(supprimé)

désolé pour la longueur du post.. mais tu m'as demandé de poster hein ;-)
--
a+

9

je continue...

il semble que je me sois planté...
voilà ce que j'obtiens après avoir éclaté la génération en plusieurs étapes..
Initialisation : 1er appel au timer
Fin etape 1 - Write(page1): durée: 0,728s
Fin etape 2 - Write(page2): durée: 2,396s
Fin etape 3 - Write(page3): durée: 1,123s
Fin etape 4 - Write(page4): durée: 3,208s
Fin etape 5 - Write(page5): durée: 2,253s
Fin etape 6 - Write(page6): durée: 1,483s
Fin etape 7 - Output(pdf-in-file): durée: 0,053s
Fin etape 8 - SendEmail(PDF): durée: 0,812s


donc pas de problème avec la génération du PDF..
ni l'envoi de l'email avec le PDF en PJ..
Par contre, dés que je décommente la redirection.. le script plante !

voici le bout de php qui finit la génération ..
...
require_once(LIB_PATH . 'udSimpleMail.class.php') ;
$myMail = &new udSimpleMail($from, $to, $subject, $return);
if(!$myMail->sendAttachment($file,$message))
{
	die('sending error!');
}

header('Content-type: application/pdf');
header("Location: ".ABS_CACHE_PATH.$file);


une idée lumineuse serait la bienvenue.. je patoge :-)
A+

10

Re.. (y a que moi ici en ce moment ;-))

Le diagnostic précédent est faux !
Le script plante de façon aléatoire dés que l'envoi d'email est validé..
Par contre, il ne plante jamais avec la redirection !

Je vais essayé la lib de Spipu (envoi d'email avec PJ), on va voir le résultat..

À suivre...

11

Après des tests avec la lib PJmail de Spipu... même résultat !!

Je suis donc coincé avec la problématique suivante :

1- généré un pdf (6 pages)
2- l'envoyer en PJ (poids du PDF ~70ko)
3- l'afficher

tout ça bien sûr sans intervention manuelle du visiteur !

quelqu'un a-t-il expérimenté avec succès cette configuration ?

A+

12

heu, la conversion prend 11 secondes ?! là y a un blem

dommage, tu as enlevé le code html et CSS, j'aurais voulu voir chez moi combien de temps il prennait... tu pourrais me les renvoyer par mail à l'adresse présent dans le _lisez_moi.txt d'html2pdf ? merci smile

par contre, si j'ai bien compris, tu crées l'html, tu le convertis en PDF, puis tu enregistres le résultat dans un fichier temporaire, tu envoies ce fichier temporaire par mail puis tu rediriges l'user vers ce fichier temporaire, c'est bien ca ?

dans ce cas là, pourquoi tu ne fais pas plutot comme ca :

- creation de l'HTML => $contentHTML
- convertion en PDF => $contenuPDF
- envoie de $contenuPDF sans ecriture dans un fichier temporaire
- un petit echo $contenuPDF avec les headers qui vont bien

comme ca, pas de redirection, et pas d'écriture inutile de fichier temporaire.
Ancien pseudo : lolo

13

ah 11s, c'est long ?
Je vais te préparer un email avec les infos..

J'essaie ça à présent.. mais ça n'envoie pas le PDF en PJ..

...
//PDF generation
$file_pdf = $html2pdf->Output();

//Email sending
require_once(INCLUDE_PATH.'pjmail\pjmail.class.php');
$mail = new PJmail();
$mail->setAllFrom('mon@mail.com', 'Ben');	// mail en cas d'erreur d'envoie
$mail->addfrom('mon@mail.com', 'Ben');		// mail envoyeur
$mail->addrecipient('dest@mail.org );
$mail->addsubject('subject');	
$mail->text = 'message';
$mail->addbinattachement('mondoc.pdf', $file_pdf);
$mail->sendmail(); 

//PDF viewing
ini_set('zlib.output_compression','0');
header('Content-type: application/pdf');
header("Pragma: public");
header('Cache-Control: private, max-age=0, must-revalidate');
readfile($file_pdf);

Le PDF s'affiche correctement dans le navigateur (IE et FFx) !

Si je change la génération PDF par :
$file_pdf = $html2pdf->Output('mondoc.pdf',true);


Le PDF est joint à l'email mais j'obtiens à nouveau :
An internal server error occurred. Please try again later.


Ralalaaaa... galère galère ! ;-)

14

voici mon nouvel essai.. ça fonctionne..

//PDF generation 
$file_pdf = $html2pdf->Output('mondoc.pdf',true); 
 
//Email sending 
require_once(INCLUDE_PATH.'pjmail\pjmail.class.php'); 
$mail = new PJmail(); 
$mail->setAllFrom('mon@mail.com', 'Ben');	// mail en cas d'erreur d'envoie 
$mail->addfrom('mon@mail.com', 'Ben');		// mail envoyeur 
$mail->addrecipient('dest@mail.org ); 
$mail->addsubject('subject');	 
$mail->text = 'message'; 
$mail->addbinattachement('mondoc.pdf', $file_pdf); 
$mail->sendmail();  
 
//PDF viewing 
header('Content-type: application/pdf');
header('Pragma: public');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Content-Length: '. strlen($file_pdf));
echo($file_pdf);

Presque...

Avec certains PDFs moins fournis, toute la procédure fonctionne (génération / envoi email / affichage).
Mais dés que le PDF est plus gros (plus d'infos à générer), ça renvoie le message d'erreur précédent.

Ça continue ..

15

je viens de regarder tes fichiers, et déjà, 2 petits points dans ton html :

- tu fermes directement tes balises pages après les avoir fermer, alors que normalement tu es censé mettre le contenu de la page à l'interieur :
<page>
  // tout le contenu
</page>


- tu utilises pas mal d'images apparemment en tant que puce, sauf que c'est des fichiers .html que tu as spécifié. est-ce normal ?
- même remarque pour le fichier css, tu appelle un fichier html ?!

enfin, pour info, sur l'ordi que j'ai ici (un vieux celeron 2,8Ghz avec 512Mo de ram, sous windows 2000 et easyphp 2.0b1, donc vraiment une config dépassée), la conversion de ton document prend 8secondes... donc si chez toi ca prend 11secondes, je pense qu'il y a un souci !

d'ailleurs, ma config HP est limité à 16Mo, et pourtant ca marche nikel...

dans ton test en ./14, quand tu dis que ca renvoie le message d'erreur, ca envoie quand même le mail avec le pdf ? car dans ce cas là, c'est vraiment zarb étant donné que les dernières instructions sont extrêmement simple....
Ancien pseudo : lolo

16

Arg.. j'ai passé le fichier par Nvu pour retirer les infos légales.. et il m'a visiblement fait du nettoyage !!!

Alors après ça, il n'y a plus les balises <page> visibles !!

Voilà une partie du fichier PHP..
//read html template file
function getHtml($htmlfile,$lang){
	$htmlFile = TPL_H_PATH . $lang . '-'.$htmlfile.'.shtml';
	$file = fopen($htmlFile,"r");
	$size_of_file = filesize($htmlFile);
	$content = fread($file, $size_of_file);
	fclose($file);
	return $content;
}

...
	/* 
	* PDF lib
	*/
	require_once(INCLUDE_PATH.'html2pdf\html2pdf.class.php');
	$html2pdf = new HTML2PDF('P','A4', 'fr', array(15,10,15,10));
...
	/*
	* PAGE 1
	*/
	//css file
	$content="<link type=\"text/css\" href=\"css/impression.css\" rel=\"stylesheet\" />";
	//get HTML page 1
	$content.= getHtml('page1',$lang);
	//replacing data in page 1
	$page1_setup='backimg="images/page1.jpg" backimgx="left" backimgy="top" backimgw="100%" backimgh="100%"';
	$content=str_replace('#page1_setup', $page1_setup,$content);
	$content=str_replace('#current_year',YEAR,$content);
	$content=str_replace('#user_firstname', stripslashes($_SESSION['user_firstname']),$content);
	$content=str_replace('#user_name', stripslashes($_SESSION['user_name']),$content);
...
	//write page 1
	$html2pdf->WriteHTML($content);

	/*
	* PAGE 2
	*/
	//get HTML page 2
	$content= getHtml('page2',$lang);
	//replacing data in page 2
...

Le fichier CSS, c'est celui que je t'ai envoyé.
Voici le template de la page 1
<!-- PAGE 1/6 Intro -->
<page #page1_setup>
	<page_footer>
		<table class="footer">
			<tr>
				<td class="footer-td1"><strong>Societe</strong></td>
			</tr>
			<tr>
				<td class="footer-td1"><a href="http://www.societe.com" class="footer-link">www.societe.com</a></td>
			</tr>
		</table>
	</page_footer>
	<div class="p1-title">
		<h1>Dossier de<br/>souscription<br/><span>#subtitle</span></h1>
		R&eacute;alis&eacute; pour #user_sex #user_firstname #user_name<br/>
		&nbsp;le #today_date<br/>
		&nbsp;<em>Offre valable jusqu'au #validation_date</em>
	</div>
	<div class="p1-asfe">
		<strong>Pour toute information,<br/>notre &eacute;quipe se tient &agrave; votre<br/>enti&egrave;re disposition :</strong><br/>
		<br/>
		#a1addr<br/>
		#a1cp #asfe1city<br/>
		#a1country<br/>
		#a1phone<br/>
		<br/>
		#a2addr<br/>
		#a2cp #asfe2city<br/>
		#a2country<br/>
		#a2phone<br/>
		<br/>
		#aemail
	</div>
</page>


Concernant mon serveur, il s'agit d'une VM (vmware) avec 512Mo RAM..
Elle tourne sur un Celeron 220 / 2Go RAM.. donc moyen en puissance.

Pour le test ./14, le PDF est toujours envoyé par email même en cas d'erreur !

Enfin, grâce à la v3.15, je pense revoir la façon d'ajouter des puces ;-)
Ça devrait me permettre de supprimer pas mal de tableaux.

17

ok, donc si quoi qu'il arrive il t'envoie quand meme le fichier PDF généré par mail, ca veut dire que le problème ne vient pas de la conversion.

utilises tu un framework (ou autre) qui utiliserait la bufferisation du contenu (style ob_start)

car dans ce cas, ca pourrait venir de là. Essaye de mettre un ob_end_flush juste avant ton echo($file_pdf);
Ancien pseudo : lolo

18

Je n'utilise pas de framework pour ce site, par contre, j'avais un appel à ob_start("ob_gzhandler"); pour toutes mes pages.
Je l'ai commenté à présent mais ça ne change rien .. toujours le même message d'erreur !!!

Mais je crois que le problème peut venir de la (mauvaise) gestion du buffer.. je patoge un peu dans ce domaine précis !

La commande ob_end_flush() ne change rien non plus.

19

essaye, une fois que tu n'as plus besoin des objets, de les supprimer : unset($html2pdf); par exemple, afin de récupérer de la mémoire au fur et à mesure. Car 128Mo c'est vraiment pas normal.... essaye de localiser ce qui prend tant de mémoire en utilisant la fonction memory_get_usage()
Ancien pseudo : lolo

20

En regardant le gestion des tâches pendant l'exécution du script, je ne vois pas d'augmentation de la RAM par contre 100% de la charge CPU.
Est-ce que je me trompe en disant que le problème ne vient pas d'un manque de mémoire ?

21

vraiment zarb en effet...

je viens de faire un test sur un serveur de prod en convertissant ton fichier HTML, j'obtiens ca :

Timer : init - Memory : 1870.9ko
Etape 1 : Timer : 0.002s - Memory : 1924.7ko
Etape 2 : Timer : 2.227s - Memory : 3363.5ko


pour le script suivant :

	echo getTimerDebug();
	$pdf = new HTML2PDF('P', 'A4', 'fr');
	echo 'Etape 1 : '.getTimerDebug();
	$pdf->WriteHTML($content, isset($_GET['vuehtml']));
	echo 'Etape 2 : '.getTimerDebug();
	$pdf->Output();


la conversion est "rapide" et ne prend que 1,5Mo de mémoire, donc c'est raisonnable

le problème doit venir d'ailleurs...

Ancien pseudo : lolo

22

Héhé.. bon on est d'accord sur le fait que la génération se déroule "normalement" (timing/ ressources mémoire) !

As-tu regarder la charge processeur ?
Ça serait intéressant de voir si tu as aussi une telle montée (100cheeky au moment de la génération !?

de mon côté avec la charge mémoire:
Initialisation : 1er appel au timer - Memory: 1.53 Mo
Fin etape 1 - Write(page1): durée: 0,762s - Memory: 4.13 Mo
Fin etape 2 - Write(page2): durée: 2,412s - Memory: 4.41 Mo
Fin etape 3 - Write(page3): durée: 1,519s - Memory: 4.39 Mo
Fin etape 4 - Write(page4): durée: 3,452s - Memory: 4.69 Mo
Fin etape 5 - Write(page5): durée: 2,376s - Memory: 4.63 Mo
Fin etape 6 - Write(page6): durée: 1,467s - Memory: 4.63 Mo
Fin etape 7 - Output(pdf-in-file): durée: 0,072s - Memory: 4.33 Mo
Fin etape 8 - SendEmail(PDF): durée: 6,069s - Memory: 4.57 Mo


Merci.

23

vivi, j'ai une telle montée, mais c'est normal. N'importe quelle page d'un site nécessitant beaucoup de calculs engendre ça. après, tant que cette page n'est pas appelée sans arrêt, ca ira. Mais il est vrai que si chez toi, ca met plus de 10 secondes à généré, et que si pendant ces 10 secondes, le proc est utilisé à 100%, ca veut dire que si quelqu'un d'autre utilise le site il en sera pénalisé... Ton serveur semble sous dimensionné pour ce que tu veux faire.

Et puis un petit détail : un serveur de production sous windows avec IIS, c'est pas vraiment top, il vaudrait vraiment mieux utiliser un LAMP (à mon boulot, on utilise des serveurs IBM x3650 sous redhat, ca marche plutot bien, et je n'ai jamais eu d'erreurs style "500 - An internal server error occurred")

aurais-tu les moyens de tester ton appli sur un autre serveur ?
Ancien pseudo : lolo

24

attends, juste comme ca, vu que ca plantait en faisant une redirection, mais egalement en faisant un echo.... tu peux juste faire un echo, mais sans aucun header avant ?
Ancien pseudo : lolo

25

Alors là, tu prêches un convaincu.. à 200%..
Seulement le client est roi, et c'est lui qui m'impose ce #$*^~# de IIS !!!
Je dois donc faire avec.. évidemment son serveur de prod n'est pas mon serveur de dev..
J'attends une remontée des 1ers tests du script dans son environnement..
mais quand même, j'aimerai comprendre ce qui ne va pas ;-)

Pour info, quand j'ai le choix, tout est en LAMP (debian ou ubuntu server).

26

du coup, j'ai pas compris, ton pb d'erreur 500, c'est sur le serveur de DEV ou de PROD, et les 2 sont sous IIS ? ou seulement celui de PROD, celui de DEV etant sous lamp ?

(juste pour être sur smile)
Ancien pseudo : lolo

27

Les 2 serveurs sont sous IIS..
Tous les tests sont menés sur mon serveur de dev (VMware sur Celeron 220 / 2Go RAM).
Désolé pour la confusion :-)

28

ok

t'as essayé ce que j'ai marqué au ./24 ?
Ancien pseudo : lolo

29

Essayé et sans meilleurs résultats .. il semble toutefois que les PDFs un peu plus complexes passent..
mais ça échoue avec les plus gros ..
et bien entendu, j'obtiens le fichier non interprété dans le navigateur (sans l'ouverture de Reader).

30

benbois (./29) :
et bien entendu, j'obtiens le fichier non interprété dans le navigateur (sans l'ouverture de Reader).

normal en effet, vu qu'il n'y a plus les headers pour indiquer que c'est un PDF
benbois (./29) :
Essayé et sans meilleurs résultats .. il semble toutefois que les PDFs un peu plus complexes passent.. mais ça échoue avec les plus gros ..


ca ressemble vraiment à un problème de capacité... le problème c'est que je ne connais pas IIS... est-ce qu'il n'y aurait pas un pb de limite d'utilisation du CPU au dela duquel ISS préfère killer php afin de ne pas pénaliser les autres utilisateurs ? ou un temps limite d'execiution autre que le time_limit de php ?
Ancien pseudo : lolo