<?php 

ini_set('display_errors', 1);ini_set('display_startup_errors', 1);error_reporting(E_ALL);//Activa ver warnings

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpWord\Shared\Converter;
use PhpOffice\PhpWord\TemplateProcessor;
use PhpOffice\PhpWord\Element\Table;

//echo 'Versión actual de PHP: ' . phpversion();echo "<br>";
//require 'functions.php';//Aqui es donde realmente esta el template y las equivalencias

//La data que se va a meter al template... se divide en 3 que son llaves normales, tablas e imagenes

//valores simples por sustituir en el template
$data = array(
    'TONAME' => "Whoever",
    'TOEMAIL' => "alexcd2000@yopmail.com",
    'FROMNAME' => "Whoever else name",
    'ID' => "88789581",
    'CSD' => "1123",
    'TIMESTAMP' => "14-11-2022 19:23"
);
//rows de tablas, el estilo y si tienes mas o menos columnas lo editas en la funcion. 
//Igual si tienes filas con rowspan 2 las pones alla en la funcion
$tabla = array(
    array(
        'name' => "Producto 12893",
        'cant'  => 4,
        'import'  => 100
    ),
    array(
        'name' => "Producto 2",
        'cant'  => 10,
        'import'  => 100
    )
);
//ruta a todas las imagenes a sustituir
$imagenes = array(
    array(
        'name' => "photo1",
        'path' => __DIR__."/img/photo1.png"
    ),
    array(
        'name' => "photo2",
        'path' => __DIR__."/img/photo2.png"
    ),
    array(
        'name' => "photo3",
        'path' => __DIR__."/img/photo3.jpg"
    )
);

$datos = array(
    'data' => $data,
    'tabla' => $tabla,
    'imagenes' => $imagenes
);

echo generateWordDocument($datos,'template.docx',"docx/"); //regresa la dirección donde se guardo

function generateWordDocument($datos,$template,$outFolder){

    $docxPath = $template;
    $template = new \PhpOffice\PhpWord\TemplateProcessor($docxPath);
    $phpWord = new \PhpOffice\PhpWord\PhpWord();
    
    //agrega los valores del array, la key debe ser igual a lo que esta en ${} en el template
    if(isset($datos['data'])){
        $i=0; foreach( $datos['data'] as $key=>$feach){
            $template->setValue($key, $feach);
        $i++;
        }
    }

    if(isset($datos['tabla'])){
        $section = $phpWord->addSection();
        //Las propiedades y estilos las ves aqui
        //https://phpword.readthedocs.io/en/latest/styles.html#table
        
        $tableCellStyle = ['valign' => 'center', 'borderBottomColor'=>"red",'borderBottomSize'=>"1"];//para las celdas
        $tableStyleCellRowSpan = ['gridSpan' => 2,  'valign' => 'center', 'bgColor' => 'f0f0f0'];//para tener celdas con rowspan mergged
        
        $paragraphStyle=['align'=>'center']; //para centrar el texto es una propiedad del parrafo, es el segundo parameetro
        $tableFontStyle = ['bold' => true];// para las fuentes
        

        $table = $section->addTable('Table');
        $table->addRow();
        $table->addCell(2000, $tableCellStyle)->addText('Cantidad', $tableFontStyle, $paragraphStyle);
        $table->addCell(5000, $tableCellStyle)->addText('Producto', $tableFontStyle);
        $table->addCell(2000, $tableCellStyle)->addText('Monto', $tableFontStyle);
        
        foreach ($datos['tabla'] as $row) {
            $table->addRow();
            //esto vas a tener que escribirlo segun el número de columnas en tu archivo
            $table->addCell(2000)->addText($row['cant']);
            $table->addCell(5000)->addText($row['name']);
            $table->addCell(2000)->addText($row['import']);
        }

        //celdas merged vas a tener que ponerlas directo en la funcion...
        $table->addRow();
        $table->addCell(2000, $tableStyleCellRowSpan)->addText("Total de total");
        $table->addCell(2000, $tableCellStyle)->addText("12654");

        $template->setComplexBlock('TABLEPRODUCTS', $table);
    }

    if(isset($datos['imagenes'])){
        //Las imagenes en el template se deben llamar siempre ${IMAGEN#}
        foreach ($datos['imagenes'] as $i => $row) {
            $template->setImageValue(sprintf('IMAGEN#%d', $i + 1), $row['path']);
        }
    }

    //La carpeta donde se guarda debe de tener permisos 777 para guardar segun el servidor
    $output = $outFolder.time().$docxPath;//el nombre y ruta donde se va a guardar
    $template->saveAs($output); 

    return $output;
}




//Ahora el código que convierte el docx a pdf

//todo el código esta aquí pero requiere libreOffice instalado en el servidor, 
//ya esta en el plesk pero si lo requieres cmd del ssh para instalarlo es: sudo apt-get install libreoffice 
$inputFolder =  "docx";
$outputFolder =  "pdf";
$curr_dir = getcwd();

try {
    $cb_show = function ($message) {
        //echo ($message);
    };
    $aPDF= docx2pdf($inputFolder, $outputFolder, $cb_show);
	//convierte todo lo que este en la carpeta por eso regresa un array
	echo "...<pre>";var_dump($aPDF);echo "</pre>...";
	
} catch (Exception $e) {
    echo ($e->getMessage());
}

class OfficeConverter
{
    /** @var string */
    private $file;
    /** @var string */
    private $bin;
    /** @var string */
    private $tempPath;
    /** @var string */
    private $extension;
    /** @var string */
    private $basename;
    /** @var bool */
    private $prefixExecWithExportHome;

    /**
     * OfficeConverter constructor.
     *
     * @param string      $filename
     * @param string|null $tempPath
     * @param string      $bin
     * @param bool        $prefixExecWithExportHome
     */
    public function __construct($filename, $tempPath = null, $bin = 'libreoffice', $prefixExecWithExportHome = true)
    {
        if ($this->open($filename)) {
            $this->setup($tempPath, $bin, $prefixExecWithExportHome);
        }
    }

    /**
     * @param string $filename
     *
     * @return string|null
     *
     * @throws OfficeConverterException
     */
    public function convertTo($filename)
    {
        $outputExtension = pathinfo($filename, PATHINFO_EXTENSION);
        $supportedExtensions = $this->getAllowedConverter($this->extension);

        if (!in_array($outputExtension, $supportedExtensions)) {
            throw new OfficeConverterException("Output extension({$outputExtension}) not supported for input file({$this->basename})");
        }

        $outdir = $this->tempPath;
        $shell = $this->exec($this->makeCommand($outdir, $outputExtension));
        if (0 != $shell['return']) {
            throw new OfficeConverterException('Convertion Failure! Contact Server Admin.');
        }

        return $this->prepOutput($outdir, $filename, $outputExtension);
    }

    /**
     * @param string $filename
     *
     * @return bool
     *
     * @throws OfficeConverterException
     */
    protected function open($filename)
    {
        if (!file_exists($filename) || false === realpath($filename)) {
            throw new OfficeConverterException('File does not exist --' . $filename);
        }

        $this->file = realpath($filename);

        return true;
    }

    /**
     * @param string|null $tempPath
     * @param string      $bin
     * @param bool        $prefixExecWithExportHome
     *
     * @return void
     *
     * @throws OfficeConverterException
     */
    protected function setup($tempPath, $bin, $prefixExecWithExportHome)
    {
        //basename
        $this->basename = pathinfo($this->file, PATHINFO_BASENAME);

        //extension
        $extension = pathinfo($this->file, PATHINFO_EXTENSION);

        //Check for valid input file extension
        if (!array_key_exists($extension, $this->getAllowedConverter())) {
            throw new OfficeConverterException('Input file extension not supported -- ' . $extension);
        }
        $this->extension = $extension;

        //setup output path
        if (null === $tempPath || !is_dir($tempPath)) {
            $tempPath = dirname($this->file);
        }

        if (false === realpath($tempPath)) {
            $this->tempPath = sys_get_temp_dir();
        } else {
            $this->tempPath = realpath($tempPath);
        }

        //binary location
        $this->bin = $bin;

        //use prefix export home or not
        $this->prefixExecWithExportHome = $prefixExecWithExportHome;
    }

    /**
     * @param string $outputDirectory
     * @param string $outputExtension
     *
     * @return string
     */
    protected function makeCommand($outputDirectory, $outputExtension)
    {
        $oriFile = escapeshellarg($this->file);
        $outputDirectory = escapeshellarg($outputDirectory);

        return "{$this->bin} --headless --convert-to {$outputExtension} {$oriFile} --outdir {$outputDirectory}";
    }

    /**
     * @param string $outdir
     * @param string $filename
     * @param string $outputExtension
     *
     * @return string|null
     */
    protected function prepOutput($outdir, $filename, $outputExtension)
    {
        $DS = DIRECTORY_SEPARATOR;
        $tmpName = ($this->extension ? basename($this->basename, $this->extension) : $this->basename . '.') . $outputExtension;
        if (rename($outdir . $DS . $tmpName, $outdir . $DS . $filename)) {
            return $outdir . $DS . $filename;
        } elseif (is_file($outdir . $DS . $tmpName)) {
            return $outdir . $DS . $tmpName;
        }

        return null;
    }

    /**
     * @param string|null $extension
     *
     * @return array|mixed
     */
    private function getAllowedConverter($extension = null)
    {
        $allowedConverter = [
            '' => ['pdf'],
            'pptx' => ['pdf'],
            'ppt' => ['pdf'],
            'pdf' => ['pdf'],
            'docx' => ['pdf', 'odt', 'html'],
            'doc' => ['pdf', 'odt', 'html'],
            'wps' => ['pdf', 'odt', 'html'],
            'dotx' => ['pdf', 'odt', 'html'],
            'docm' => ['pdf', 'odt', 'html'],
            'dotm' => ['pdf', 'odt', 'html'],
            'dot' => ['pdf', 'odt', 'html'],
            'odt' => ['pdf', 'html'],
            'xlsx' => ['pdf'],
            'xls' => ['pdf'],
            'png' => ['pdf'],
            'jpg' => ['pdf'],
            'jpeg' => ['pdf'],
            'jfif' => ['pdf'],
            'PPTX' => ['pdf'],
            'PPT' => ['pdf'],
            'PDF' => ['pdf'],
            'DOCX' => ['pdf', 'odt', 'html'],
            'DOC' => ['pdf', 'odt', 'html'],
            'WPS' => ['pdf', 'odt', 'html'],
            'DOTX' => ['pdf', 'odt', 'html'],
            'DOCM' => ['pdf', 'odt', 'html'],
            'DOTM' => ['pdf', 'odt', 'html'],
            'DOT' => ['pdf', 'odt', 'html'],
            'ODT' => ['pdf', 'html'],
            'XLSX' => ['pdf'],
            'XLS' => ['pdf'],
            'PNG' => ['pdf'],
            'JPG' => ['pdf'],
            'JPEG' => ['pdf'],
            'JFIF' => ['pdf'],
            'Pptx' => ['pdf'],
            'Ppt' => ['pdf'],
            'Pdf' => ['pdf'],
            'Docx' => ['pdf', 'odt', 'html'],
            'Doc' => ['pdf', 'odt', 'html'],
            'Wps' => ['pdf', 'odt', 'html'],
            'Dotx' => ['pdf', 'odt', 'html'],
            'Docm' => ['pdf', 'odt', 'html'],
            'Dotm' => ['pdf', 'odt', 'html'],
            'Dot' => ['pdf', 'odt', 'html'],
            'Ddt' => ['pdf', 'html'],
            'Xlsx' => ['pdf'],
            'Xls' => ['pdf'],
            'Png' => ['pdf'],
            'Jpg' => ['pdf'],
            'Jpeg' => ['pdf'],
            'Jfif' => ['pdf'],
            'rtf'  => ['docx', 'txt', 'pdf'],
            'txt'  => ['pdf', 'odt', 'doc', 'docx', 'html'],
        ];

        if (null !== $extension) {
            if (isset($allowedConverter[$extension])) {
                return $allowedConverter[$extension];
            }

            return [];
        }

        return $allowedConverter;
    }

    /**
     * More intelligent interface to system calls.
     *
     * @see http://php.net/manual/en/function.system.php
     *
     * @param string $cmd
     * @param string $input
     *
     * @return array
     */
    private function exec($cmd, $input = '')
    {
        // Cannot use $_SERVER superglobal since that's empty during UnitUnishTestCase
        // getenv('HOME') isn't set on Windows and generates a Notice.
        if ($this->prefixExecWithExportHome) {
            $home = getenv('HOME');
            if (!is_writable($home)) {
                $cmd = 'export HOME=/tmp && ' . $cmd;
            }
        }
        $process = proc_open($cmd, [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);

        if (false === $process) {
            throw new OfficeConverterException('Cannot obtain ressource for process to convert file');
        }

        fwrite($pipes[0], $input);
        fclose($pipes[0]);
        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        $rtn = proc_close($process);

        return [
            'stdout' => $stdout,
            'stderr' => $stderr,
            'return' => $rtn,
        ];
    }
}

class OfficeConverterException extends \Exception
{
}

function docx2pdf($input, $output, $cb_show = null)
{
	$listos=array();
    global $curr_dir;    
    $is_window_server = true;
    $directory_separator = '\\';
    $separator = " ";
    $quotes = "\"";
    if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
       $is_window_server = false;
       $directory_separator = '/';
    }
    $full_output = $curr_dir . $directory_separator . $output;
    $full_input = $curr_dir . $directory_separator . $input;
    clearstatcache();
    if (!file_exists($full_output)) {
        mkdir($full_output, 0775, true);
    }
    $files = scandir($full_input);
    $extension = [];
    for ($i = 2; $i < count($files); $i++) {
        array_push($extension, pathinfo($files[$i], PATHINFO_EXTENSION));
    }
    if ((!in_array("docx", $extension) && !!in_array("doc", $extension)) || !file_exists($full_input)) {
        throw new \Exception("No files to convert!<br/>");
    }
    for ($i = 2; $i < count($files); $i++) {
        $filename = pathinfo($files[$i], PATHINFO_FILENAME);
        $ext = pathinfo($files[$i], PATHINFO_EXTENSION);
        if ($ext == "docx" || $ext == "doc") {
            if($is_window_server){
                $command = $curr_dir . '\libreoffice\LibreOfficePortable.exe --headless --convert-to pdf:writer_pdf_Export --outdir ' . $output . $separator . $quotes . $full_input . $directory_separator . $files[$i] .$quotes;
                echo($command . "<br/>");                
                exec($command); 
                $cb_show("Converting file $files[$i] to pdf! <br/>");               
            }
            else{
                $converter = new OfficeConverter($full_input . $directory_separator . $files[$i]);
                $full_file_name = $filename . '.pdf';
                $converter->convertTo($full_file_name);
                rename($full_input . $directory_separator . $full_file_name, $full_output . $directory_separator .$full_file_name);                
                $cb_show("Converting file $files[$i] to pdf! <br/>");
            }             
			$listos[]=$output."/".$files[$i];
			unlink($input."/".$files[$i]);
        }
    }
    $cb_show("Convert Done!");
	return $listos;
}



?>