Browse Source

Debug to make MAIN_ODT_AS_PDF workign with unoconv

Laurent Destailleur 7 years ago
parent
commit
d404d8be9f
2 changed files with 89 additions and 31 deletions
  1. 63 26
      htdocs/includes/odtphp/odf.php
  2. 26 5
      scripts/odt2pdf/odt2pdf.sh

+ 63 - 26
htdocs/includes/odtphp/odf.php

@@ -36,14 +36,14 @@ class Odf
 	protected $images = array();
 	protected $vars = array();
 	protected $segments = array();
-	
+
 	public $creator;
 	public $title;
 	public $subject;
 	public $userdefined=array();
-	
+
 	const PIXEL_TO_CM = 0.026458333;
-	
+
 	/**
 	 * Class constructor
 	 *
@@ -113,7 +113,7 @@ class Odf
 
 		copy($filename, $this->tmpfile);
 
-		// Now file has been loaded, we must move the [!-- BEGIN and [!-- END tags outside the 
+		// Now file has been loaded, we must move the [!-- BEGIN and [!-- END tags outside the
 		// <table:table-row tag and clean bad lines tags.
 		$this->_moveRowSegments();
 	}
@@ -124,7 +124,7 @@ class Odf
 	 * @param string   $key        Name of the variable within the template
 	 * @param string   $value      Replacement value
 	 * @param bool     $encode     If true, special XML characters are encoded
-	 * @param string   $charset    Charset  
+	 * @param string   $charset    Charset
 	 * @throws OdfException
 	 * @return odf
 	 */
@@ -211,7 +211,7 @@ class Odf
 	{
 		preg_match_all('/[\{\<]\?(php)?\s+(?P<content>.+)\?[\}\>]/iU',$this->contentXml, $matches); // detecting all {?php code ?} or <?php code ? >
 		$nbfound=count($matches['content']);
-		for ($i=0; $i < $nbfound; $i++) 
+		for ($i=0; $i < $nbfound; $i++)
 		{
 			try {
 				$ob_output = ''; // flush the output for each code. This var will be filled in by the eval($code) and output buffering : any print or echo or output will be redirected into this variable
@@ -268,7 +268,7 @@ IMG;
 	    $this->contentXml = preg_replace('/\[!--\sBEGIN<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- BEGIN \\1 --]', $this->contentXml);
 	    // Replace END<text:s/>xxx into END xxx
 	    $this->contentXml = preg_replace('/\[!--\sEND<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- END \\1 --]', $this->contentXml);
-    
+
 	    // Search all possible rows in the document
 		$reg1 = "#<table:table-row[^>]*>(.*)</table:table-row>#smU";
 		preg_match_all($reg1, $this->contentXml, $matches);
@@ -302,7 +302,7 @@ IMG;
 	    // Search all tags fou into condition to complete $this->vars, so we will proceed all tests even if not defined
 	    $reg='@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU';
 	    preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER);
-	    
+
 	    //var_dump($this->vars);exit;
 	    foreach($matches as $match)   // For each match, if there is no entry into this->vars, we add it
 		{
@@ -312,7 +312,7 @@ IMG;
 			}
 	    }
 	    //var_dump($this->vars);exit;
-	    
+
 		// Conditionals substitution
 		// Note: must be done before static substitution, else the variable will be replaced by its value and the conditional won't work anymore
 	    foreach($this->vars as $key => $value)
@@ -358,7 +358,7 @@ IMG;
 		if ($type == 'content')	$this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml);
 		if ($type == 'styles')	$this->stylesXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->stylesXml);
 		if ($type == 'meta')	$this->metaXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->metaXml);
-		
+
 	}
 
 	/**
@@ -467,7 +467,7 @@ IMG;
 
 		$this->setMetaData();
 		//print $this->metaXml;exit;
-		
+
 		if (! $this->file->addFromString('content.xml', $this->contentXml)) {
 			throw new OdfException('Error during file export addFromString content');
 		}
@@ -477,7 +477,7 @@ IMG;
 		if (! $this->file->addFromString('styles.xml', $this->stylesXml)) {
 			throw new OdfException('Error during file export addFromString styles');
 		}
-		
+
 		foreach ($this->images as $imageKey => $imageValue) {
 			// Add the image inside the ODT document
 			$this->file->addFile($imageKey, 'Pictures/' . $imageValue);
@@ -499,12 +499,12 @@ IMG;
 	public function setMetaData()
 	{
 	    if (empty($this->creator)) $this->creator='';
-	    
+
 		$this->metaXml = preg_replace('/<dc:date>.*<\/dc:date>/', '<dc:date>'.gmdate("Y-m-d\TH:i:s").'</dc:date>', $this->metaXml);
 		$this->metaXml = preg_replace('/<dc:creator>.*<\/dc:creator>/', '<dc:creator>'.htmlspecialchars($this->creator).'</dc:creator>', $this->metaXml);
 		$this->metaXml = preg_replace('/<dc:title>.*<\/dc:title>/', '<dc:title>'.htmlspecialchars($this->title).'</dc:title>', $this->metaXml);
 		$this->metaXml = preg_replace('/<dc:subject>.*<\/dc:subject>/', '<dc:subject>'.htmlspecialchars($this->subject).'</dc:subject>', $this->metaXml);
-		
+
 		if (count($this->userdefined))
 		{
 		    foreach($this->userdefined as $key => $val)
@@ -515,7 +515,7 @@ IMG;
 		    }
 		}
 	}
-	
+
 	/**
 	 * Update Manifest file according to added image files
 	 *
@@ -569,24 +569,58 @@ IMG;
 	{
 		global $conf;
 
-		if( $name == "" ) $name = md5(uniqid());
+		if( $name == "" ) $name = "temp".md5(uniqid());
 
 		dol_syslog(get_class($this).'::exportAsAttachedPDF $name='.$name, LOG_DEBUG);
 		$this->saveToDisk($name);
 
 		$execmethod=(empty($conf->global->MAIN_EXEC_USE_POPEN)?1:2);	// 1 or 2
+		// Method 1 sometimes hang the server.
 
-		$name=preg_replace('/\.odt/i', '', $name);
-		if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT))
+		if (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF))
 		{
-			$command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF);
+			// If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87
+
+			// MAIN_ODT_AS_PDF should be   "sudo -u unoconv /usr/bin/unoconv" and userunoconv must have sudo to be root by adding file /etc/sudoers.d/unoconv with content  www-data ALL=(unoconv) NOPASSWD: /usr/bin/unoconv .
+
+			// Try this with www-data user:    /usr/bin/unoconv -vvvv -f pdf /tmp/document-example.odt
+			// It must return:
+			//Verbosity set to level 4
+			//Using office base path: /usr/lib/libreoffice
+			//Using office binary path: /usr/lib/libreoffice/program
+			//DEBUG: Connection type: socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext
+			//DEBUG: Existing listener not found.
+			//DEBUG: Launching our own listener using /usr/lib/libreoffice/program/soffice.bin.
+			//LibreOffice listener successfully started. (pid=9287)
+			//Input file: /tmp/document-example.odt
+			//unoconv: file `/tmp/document-example.odt' does not exist.
+			//unoconv: RuntimeException during import phase:
+			//Office probably died. Unsupported URL <file:///tmp/document-example.odt>: "type detection failed"
+			//DEBUG: Terminating LibreOffice instance.
+			//DEBUG: Waiting for LibreOffice instance to exit
+
+			// It fails:
+			// - set shel of user to bash instead of nologin.
+			// - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back
+
+			$command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name);
+			//$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name);
 		}
 		else
 		{
-		    dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING);
-			$command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF);
-		}
+			// deprecated old method
+			$name=preg_replace('/\.odt/i', '', $name);
 
+			if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT))
+			{
+				$command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF);
+			}
+			else
+			{
+			    dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING);
+				$command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF);
+			}
+		}
 
 		//$dirname=dirname($name);
 		//$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname;
@@ -598,16 +632,19 @@ IMG;
 		}
 		if ($execmethod == 2)
 		{
+			$outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
+
 			$ok=0;
 			$handle = fopen($outputfile, 'w');
 			if ($handle)
 			{
 				dol_syslog(get_class($this)."Run command ".$command,LOG_DEBUG);
+				fwrite($handle, $command."\n");
 				$handlein = popen($command, 'r');
 				while (!feof($handlein))
 				{
 					$read = fgets($handlein);
-					fwrite($handle,$read);
+					fwrite($handle, $read);
 					$output_arr[]=$read;
 				}
 				pclose($handlein);
@@ -616,7 +653,7 @@ IMG;
 			if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
 		}
 
-		if($retval == 0)
+		if ($retval == 0)
 		{
 			dol_syslog(get_class($this).'::exportAsAttachedPDF $ret_val='.$retval, LOG_DEBUG);
 			if (headers_sent($filename, $linenum)) {
@@ -686,7 +723,7 @@ IMG;
 
 	/**
 	 * Empty the temporary working directory recursively
-	 * 
+	 *
 	 * @param  string  $dir    The temporary working directory
 	 * @return void
 	 */
@@ -709,7 +746,7 @@ IMG;
 
 	/**
 	 * return the value present on odt in [valuename][/valuename]
-	 * 
+	 *
 	 * @param  string $valuename   Balise in the template
 	 * @return string              The value inside the balise
 	 */

+ 26 - 5
scripts/odt2pdf/odt2pdf.sh

@@ -3,20 +3,26 @@
 # @copyright  GPL License 2013 - Florian HEnry - florian.henry@open-concept.pro
 # @copyright  GPL License 2017 - Laurent Destailleur - eldy@users.sourceforge.net
 #
-# Convert an ODT into a PDF using "jodconverter" or "pyodconverter" tool.
-# Dolibarr variable MAIN_ODT_AS_PDF must be defined to value "jodconverter" to call jodconverter wrapper after ODT generation
+# Convert an ODT into a PDF using "jodconverter" or "pyodconverter" or "unoconv" tool.
+# Dolibarr variable MAIN_ODT_AS_PDF must be defined 
+#  to value "unoconv" to call unoconv CLI tool after ODT generation.
 #  or value "pyodconverter" to call DocumentConverter.py after ODT generation.
+#  or value "jodconverter" to call jodconverter wrapper after ODT generation
 #  or value "/pathto/jodconverter-cli-file.jar" to call jodconverter java tool without wrapper after ODT generation.
 # Dolibarr variable MAIN_DOL_SCRIPTS_ROOT must be defined to path of script directories (otherwise dolibarr will try to guess).
 
 
 if [ "x$1" == "x" ] 
 then
-	echo "Usage:   odt2pdf.sh fullfilename [jodconverter|pyodconverter|pathtojodconverterjar]"
+	echo "Usage:   odt2pdf.sh fullfilename [unoconv|jodconverter|pyodconverter|pathtojodconverterjar]"
+	echo "Example: odt2pdf.sh myfile unoconv"
 	echo "Example: odt2pdf.sh myfile ~/jodconverter/jodconverter-cli-2.2.2.jar"
 	exit
 fi
 
+
+
+
 # Full patch where soffice is installed 
 soffice="/usr/bin/soffice"
 
@@ -26,7 +32,21 @@ home_java="/tmp"
 
 # Main program
 if [ -f "$1.odt" ]
- then
+then
+
+  if [ "x$2" == "xunoconv" ]
+  then
+      # See issue https://github.com/dagwieers/unoconv/issues/87
+      /usr/bin/unoconv -vvv "$1.odt"
+      retcode=$?
+	  if [ $retcode -ne 0 ]
+	   then
+	    echo "Error while converting odt to pdf: $retcode"
+	    exit 1
+	  fi
+	  exit 0
+  fi
+
   nbprocess=$(pgrep -c soffice)
   if [ $nbprocess -ne 1 ]	# If there is some soffice process running
    then
@@ -59,8 +79,9 @@ if [ -f "$1.odt" ]
     echo "Error while converting odt to pdf: $retcode"
     exit 1
   fi
+  
   sleep 1
- else
+else
   echo "Error: Odt file $1.odt does not exist"
   exit 1
 fi