<?php 
/**
	Classe de génération des PDF à partir d'un flux html.
	Fonctionne sous linux et windows, necessite les binaires wkhtml placés dans "erp\lib\wkhtmltopdf"
	
	Sous linux : 
	sudo apt-get install wkhtmltopdf
	sudo chmod a+x /usr/local/bin/wkhtmltopdf
	sudo apt-get install openssl build-essential xorg libssl-dev
	sudo apt-get install xvfb
	echo xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@" > /usr/local/bin/wkhtmltopdf.sh
	sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh

	ex utilisation : 

	$pdf = new Pdf('<h1>Hello World</h1>');
	$pdf->orientation = 'Landscape';

	header('Content-Type: application/pdf');
	header('Content-Disposition: attachment; filename="my.pdf"');
	echo $pdf->generate();


	Pour ajouter un header, il faut ajouter les éléments suivants :
	<!-- #header --> avant le contenu du header
	<!-- /header --> après le contenu du header
	
	De même avec le footer (remplacer header par footer)
	
	@author v.carruesco, v.morreel
	@version 2.0
**/
class Pdf{
	public $html,$orientation,$margin,$css;

	function __construct($html = null){
		$this->orientation = 'Portrait';
		$this->html = $html;
		$this->format = 'A4';
		$this->margin = (object) array(
			'top' => '10',
			'right' => '10',
			'bottom' => '10',
			'left' => '10'
		);
	}


		// Retourne (uniquement sur les pdf avec texte editable) la liste des champs editable
	// du pdf spécifié et leurs valeurs. Si le parametre onlyfdf est a true, la méthode retournera
	// le format fdf brut (utile uniquement pour du débug ou pour de l'interne)
	// NB : Penser a installer ``apt-get install pdftk`` (ou pdftk pour windows) sur le système avant de lancer ce script
	public static function extractData($file,$onlyfdf = false){
		$data = dirname($file).DIRECTORY_SEPARATOR.'data.fdf';
		$command = 'pdftk '.$file.' generate_fdf output -';
		$datastream = shell_exec($command);
		if($onlyfdf) return $datastream;
		preg_match_all('|\/V ([^\n]*)\n\/T \(([^\n]*)\)|iUsm', $datastream, $matches,PREG_SET_ORDER);
		$parameters = array();
		foreach ($matches as $match) {
			if(count($match)==3)
			$parameters[$match[2]] = $match[1];
		}
		return $parameters;
	}

	// Utilise le pdf $file comme modèle (uniquement un pdf avec texte editable) et le remplis avec le tableau clé valeur $parameters
	// puis retourne le flux du pdf remplis.
	// Mettre la valeur /Yes pour les checkbox cochées ou / pour les décochées
	// L'argument $flat, définit si le document final doit être a plat ou encore editable
	// NB : Penser a installer ``apt-get install pdftk`` (ou pdftk pour windows) sur le système avant de lancer ce script
	public static function fillData($file,$parameters,$flat = false){
		$fdf = self::extractData($file,true);
		$fdf = preg_replace_callback('|\/V ([^\n]*)\n\/T \(([^\n]*)\)|ism',function($m) use ($parameters){
			$return = '/V ';
			$value = isset($parameters[$m[2]]) ? $parameters[$m[2]]: '';
			if($value=='/'){
				$return .= $value;
			}else{
				$return .= '('.$value.')';
			}
			$return .= PHP_EOL;
			$return .= '/T ('.$m[2].')';
			return $return;
		},$fdf);

		$command = 'echo "'.str_replace('"','\"',$fdf).'"| pdftk '.$file.' fill_form - output -';
		if($flat) $command.=' flatten';
		$datastream = shell_exec($command);
		return $datastream;
	}

	public function generate(){
		$fileName = time().mt_rand(0,100);
		if(!file_exists(File::dir().'tmp')) mkdir(File::dir().'tmp');
		$bodyPath = File::dir().'tmp'.SLASH.$fileName.'.html';
		$pdfPath = File::dir().'tmp'.SLASH.$fileName.'.pdf';

		$body = $this->html;
		$head = '';
		$foot = '';

		//Récupération du head html
        if(preg_match("/<!DOCTYPE.*<body.*>/isU", $body, $match))
        	$head = $match[0];

        //Récupération du footer html
        if(preg_match("/<\/body>.*<\/html>/isU", $body, $match))
        	$foot = $match[0];

		//Récupération du header pdf
        if(preg_match("/<!--[\s\t\r\n]*#header[\s\t\r\n]*-->(.*)<!--[\s\t\r\n]*\/header[\s\t\r\n]*-->/isU", $body, $match))
        	$header = $match[0];

        //Récupération du footer pdf 
        if(preg_match("/<!--[\s\t\r\n]*#footer[\s\t\r\n]*-->(.*)<!--[\s\t\r\n]*\/footer[\s\t\r\n]*-->/isU", $body, $match))
        	$footer = $match[0];

        //Récupération du body
        if(isset($header)){
        	$body = str_replace($header, '', $body);
        	$header = $head.$header.$foot;
        }
        if(isset($footer)){
        	$body = str_replace($footer, '', $body);
        	$footer = $head.$footer.$foot;
        }

		file_put_contents($bodyPath, $body);
		$outcmd = array();

		$cmd = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? '"C:'.SLASH.'Program Files'.SLASH.'wkhtmltopdf'.SLASH.'bin'.SLASH.'wkhtmltopdf.exe" ' : "/usr/local/bin/wkhtmltopdf.sh ";
		$cmd .= '-s '.$this->format.' -O '.$this->orientation.' -T '.$this->margin->top.' -R '.$this->margin->right.' -B '.$this->margin->bottom.' -L '.$this->margin->left;
		$cmd .= ' -d 100 --print-media-type ';
		$cmd .= ' --user-style-sheet '.dirname(__FILE__).'/../'.$this->css.' --enable-javascript ';
		
		if(isset($header)) {
			$headerPath = File::dir().'tmp'.SLASH.'header-'.$fileName.'.html';
			file_put_contents($headerPath, $header);
			$cmd .= ' --header-html '.$headerPath.' --header-spacing 5 --margin-top 35';
		}
		if(isset($footer)) {
			$footerPath = File::dir().'tmp'.SLASH.'footer-'.$fileName.'.html';
			file_put_contents($footerPath, $footer);
			$cmd .= ' --footer-html '.$footerPath.' --footer-spacing 5 --margin-bottom 35';
		}
		$cmd .= ' --footer-right "[page] / [toPage]" --footer-font-size 8 ';
		$cmd .= $bodyPath.' '.$pdfPath;

		exec($cmd, $outcmd);
		$stream = file_get_contents($pdfPath);

		if(isset($header)) unlink($headerPath);
		if(isset($footer)) unlink($footerPath);
		unlink($bodyPath);
		unlink($pdfPath);
		return $stream;
	}
}

?>