Pdf.class.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /**
  3. Classe de génération des PDF à partir d'un flux html.
  4. Fonctionne sous linux et windows, necessite les binaires wkhtml placés dans "erp\lib\wkhtmltopdf"
  5. Sous linux :
  6. sudo wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
  7. sudo tar xvf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
  8. sudo mv wkhtmltox/bin/wkhtmlto* /usr/bin/
  9. sudo ln -nfs /usr/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
  10. sudo chmod a+x /usr/local/bin/wkhtmltopdf
  11. sudo apt-get install openssl build-essential xorg libssl-dev
  12. sudo apt-get install xvfb
  13. echo xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@" > /usr/local/bin/wkhtmltopdf.sh
  14. sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
  15. ex utilisation :
  16. $pdf = new Pdf('<h1>Hello World</h1>');
  17. $pdf->orientation = 'Landscape';
  18. header('Content-Type: application/pdf');
  19. header('Content-Disposition: attachment; filename="my.pdf"');
  20. echo $pdf->generate();
  21. Pour ajouter un header, il faut ajouter les éléments suivants :
  22. <!-- #header --> avant le contenu du header
  23. <!-- /header --> après le contenu du header
  24. De même avec le footer (remplacer header par footer)
  25. @author v.carruesco, v.morreel
  26. @version 2.0
  27. **/
  28. class Pdf{
  29. public $html,$orientation,$margin,$css;
  30. function __construct($html = null, $margin = array(), $format = 'A4', $orientation = 'Portrait'){
  31. $this->html = $html;
  32. $this->margin = (object) array(
  33. 'top' => isset($margin['top']) ? $margin['top'] : '10',
  34. 'right' => isset($margin['right']) ? $margin['right'] : '10',
  35. 'bottom' => isset($margin['bottom']) ? $margin['bottom'] : '10',
  36. 'left' => isset($margin['left']) ? $margin['left'] : '10'
  37. );
  38. $this->format = $format;
  39. $this->orientation = $orientation;
  40. }
  41. // Retourne (uniquement sur les pdf avec texte editable) la liste des champs editable
  42. // du pdf spécifié et leurs valeurs. Si le parametre onlyfdf est a true, la méthode retournera
  43. // le format fdf brut (utile uniquement pour du débug ou pour de l'interne)
  44. // NB : Penser a installer ``apt-get install pdftk`` (ou pdftk pour windows) sur le système avant de lancer ce script
  45. public static function extractData($file,$onlyfdf = false){
  46. $command = 'pdftk '.$file.' generate_fdf output -';
  47. $datastream = shell_exec($command);
  48. if($onlyfdf) return $datastream;
  49. preg_match_all('|\/V ([^\n]*)\n\/T \(([^\n]*)\)|iUsm', $datastream, $matches,PREG_SET_ORDER);
  50. $parameters = array();
  51. foreach ($matches as $match) {
  52. if(count($match)==3)
  53. $parameters[$match[2]] = $match[1];
  54. }
  55. return $parameters;
  56. }
  57. // Utilise le pdf $file comme modèle (uniquement un pdf avec texte editable) et le remplis avec le tableau clé valeur $parameters
  58. // puis retourne le flux du pdf remplis.
  59. // Mettre la valeur /Yes pour les checkbox cochées ou / pour les décochées
  60. // L'argument $flat, définit si le document final doit être a plat ou encore editable
  61. // NB : Penser a installer ``apt-get install pdftk`` (ou pdftk pour windows) sur le système avant de lancer ce script
  62. public static function fillData($file,$parameters,$flat = false){
  63. $fdf = self::extractData($file,true);
  64. $fdf = preg_replace_callback('|\/V ([^\n]*)\n\/T \(([^\n]*)\)|ism',function($m) use ($parameters){
  65. $return = '/V ';
  66. $value = isset($parameters[$m[2]]) ? $parameters[$m[2]]: '';
  67. if($value=='/'){
  68. $return .= $value;
  69. }else{
  70. $return .= '('.$value.')';
  71. }
  72. $return .= PHP_EOL;
  73. $return .= '/T ('.$m[2].')';
  74. return $return;
  75. },$fdf);
  76. //$command = 'echo "'.str_replace('"','\"',$fdf).'"| pdftk '.$file.' fill_form - output -';
  77. $fdfPath = File::temp().rand(0,10000).'fdf';
  78. $pdfPath = File::temp().rand(0,10000).'pdf';
  79. file_put_contents($fdfPath, $fdf);
  80. $command = 'pdftk '.$file.' fill_form '.$fdfPath.' output "'.$pdfPath.'"';
  81. if($flat) $command.=' flatten';
  82. shell_exec($command);
  83. $datastream = file_get_contents($pdfPath);
  84. unlink($pdfPath);
  85. unlink($fdfPath);
  86. return $datastream;
  87. }
  88. /*
  89. Convertis le tableau de chemin d'images fournis en un PDF
  90. Prérequis systeme :
  91. - Installer le paquet imagemagick (apt-get install imagemagick)
  92. nb: Si le pb "convert-im6.q16: not authorized `outfile.pdf' @ error/constitute.c/WriteImage/1037" apparait
  93. editer /etc/ImageMagick-6/policy.xml et changer sur la ligne "<policy domain="coder" rights="none" pattern="PDF" />" PDF le droit none à read|write .*/
  94. public static function fromImage($images,$pdfPath){
  95. return Image::toPdf($images,$pdfPath);
  96. }
  97. public function generate($alt = false){
  98. $fileName = time().mt_rand(0,100);
  99. if(!file_exists(File::dir().'tmp')) mkdir(File::dir().'tmp');
  100. $bodyPath = File::dir().'tmp'.SLASH.$fileName.'.html';
  101. $pdfPath = File::dir().'tmp'.SLASH.$fileName.'.pdf';
  102. $body = $this->html;
  103. $head = '';
  104. $foot = '';
  105. if($alt) {
  106. //Récupération des actions URL html
  107. if(preg_match_all("/url\((\'|\")(.*)(\"|\')/U", $body, $match)) {
  108. $urls = $match[2];
  109. foreach ($urls as $key => $url) {
  110. if (preg_match("/asset=(.*.woff(2?))/i", $url, $asset)) {
  111. $path = get_asset_absolute_path($asset[1]);
  112. $body = str_replace($url, $path, $body);
  113. }
  114. }
  115. }
  116. }
  117. //Récupération du head html
  118. if(preg_match("/<!DOCTYPE.*<body.*>/isU", $body, $match))
  119. $head = $match[0];
  120. //Récupération du footer html
  121. if(preg_match("/<\/body>.*<\/html>/isU", $body, $match))
  122. $foot = $match[0];
  123. //Récupération du header pdf
  124. if(preg_match("/<!--[\s\t\r\n]*#header[\s\t\r\n]*-->(.*)<!--[\s\t\r\n]*\/header[\s\t\r\n]*-->/isU", $body, $match))
  125. $header = $match[0];
  126. //Récupération du footer pdf
  127. if(preg_match("/<!--[\s\t\r\n]*#footer[\s\t\r\n]*-->(.*)<!--[\s\t\r\n]*\/footer[\s\t\r\n]*-->/isU", $body, $match))
  128. $footer = $match[0];
  129. //Récupération du body
  130. if(isset($header)){
  131. $body = str_replace($header, '', $body);
  132. $header = $head.$header.$foot;
  133. }
  134. if(isset($footer)){
  135. $body = str_replace($footer, '', $body);
  136. $footer = $head.$footer.$foot;
  137. }
  138. file_put_contents($bodyPath, $body);
  139. $outcmd = array();
  140. $cmd = get_OS() === 'WIN' ? '"C:'.SLASH.'Program Files'.SLASH.'wkhtmltopdf'.SLASH.'bin'.SLASH.'wkhtmltopdf.exe" ' : "/usr/local/bin/wkhtmltopdf.sh ";
  141. $cmd .= '-s '.$this->format.' -O '.$this->orientation.' -T '.$this->margin->top.' -R '.$this->margin->right.' -B '.$this->margin->bottom.' -L '.$this->margin->left;
  142. $cmd .= ' -d 100 --print-media-type ';
  143. $cmd .= ' --user-style-sheet '.dirname(__FILE__).'/../'.$this->css.' --enable-javascript --javascript-delay 1000 ';
  144. if(isset($header)) {
  145. $headerPath = File::dir().'tmp'.SLASH.'header-'.$fileName.'.html';
  146. file_put_contents($headerPath, $header);
  147. $cmd .= ' --header-html '.$headerPath.' --header-spacing 5';
  148. }
  149. if(isset($footer)) {
  150. $footerPath = File::dir().'tmp'.SLASH.'footer-'.$fileName.'.html';
  151. file_put_contents($footerPath, $footer);
  152. $cmd .= ' --footer-html '.$footerPath.' --footer-spacing 5';
  153. }
  154. $cmd .= ' --footer-right "[page] / [toPage]" --footer-font-size 8 ';
  155. $cmd .= $bodyPath.' '.$pdfPath;
  156. exec($cmd, $outcmd);
  157. $stream = file_get_contents($pdfPath);
  158. if(isset($header)) unlink($headerPath);
  159. if(isset($footer)) unlink($footerPath);
  160. unlink($bodyPath);
  161. unlink($pdfPath);
  162. return $stream;
  163. }
  164. }
  165. ?>