2010-02-15 23:39:13 +01:00
< ? php
2017-04-29 01:01:12 +02:00
2010-02-15 23:39:13 +01:00
require 'Segment.php' ;
2017-04-29 01:01:12 +02:00
2010-02-15 23:39:13 +01:00
class OdfException extends Exception
2017-04-29 01:01:12 +02:00
{
}
2010-02-15 23:39:13 +01:00
/**
* Templating class for odt file
* You need PHP 5.2 at least
* You need Zip Extension or PclZip library
*
2017-04-29 01:01:12 +02:00
* @ copyright 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska ( http :// www . anaska . com )
* @ copyright 2010 - 2015 - Laurent Destailleur - eldy @ users . sourceforge . net
* @ copyright 2010 - Vikas Mahajan - http :// vikasmahajan . wordpress . com
* @ copyright 2012 - Stephen Larroque - lrq3000 @ gmail . com
2019-09-23 21:55:30 +02:00
* @ license https :// www . gnu . org / copyleft / gpl . html GPL License
2015-09-05 00:43:13 +02:00
* @ version 1.5 . 0
2010-02-15 23:39:13 +01:00
*/
class Odf
{
2010-03-13 17:05:36 +01:00
protected $config = array (
2013-04-20 11:03:23 +02:00
'ZIP_PROXY' => 'PclZipProxy' , // PclZipProxy, PhpZipProxy
'DELIMITER_LEFT' => '{' ,
'DELIMITER_RIGHT' => '}' ,
'PATH_TO_TMP' => '/tmp'
);
protected $file ;
protected $contentXml ; // To store content of content.xml file
2015-09-05 00:43:13 +02:00
protected $metaXml ; // To store content of meta.xml file
2013-04-20 11:03:23 +02:00
protected $stylesXml ; // To store content of styles.xml file
protected $manifestXml ; // To store content of META-INF/manifest.xml file
protected $tmpfile ;
protected $tmpdir = '' ;
protected $images = array ();
protected $vars = array ();
protected $segments = array ();
2017-10-10 18:54:30 +02:00
2015-09-05 00:43:13 +02:00
public $creator ;
public $title ;
public $subject ;
public $userdefined = array ();
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
const PIXEL_TO_CM = 0.026458333 ;
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
/**
* Class constructor
*
2017-04-29 01:01:12 +02:00
* @ param string $filename The name of the odt file
* @ param string $config Array of config data
2013-04-20 11:03:23 +02:00
* @ throws OdfException
*/
public function __construct ( $filename , $config = array ())
{
clearstatcache ();
if ( ! is_array ( $config )) {
throw new OdfException ( 'Configuration data must be provided as array' );
}
foreach ( $config as $configKey => $configValue ) {
if ( array_key_exists ( $configKey , $this -> config )) {
$this -> config [ $configKey ] = $configValue ;
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
}
2010-03-13 17:05:36 +01:00
2013-04-20 11:03:23 +02:00
$md5uniqid = md5 ( uniqid ());
if ( $this -> config [ 'PATH_TO_TMP' ]) $this -> tmpdir = preg_replace ( '|[\/]$|' , '' , $this -> config [ 'PATH_TO_TMP' ]); // Remove last \ or /
$this -> tmpdir .= ( $this -> tmpdir ? '/' : '' ) . $md5uniqid ;
$this -> tmpfile = $this -> tmpdir . '/' . $md5uniqid . '.odt' ; // We keep .odt extension to allow OpenOffice usage during debug.
2010-05-12 19:15:02 +02:00
2013-04-20 11:03:23 +02:00
// A working directory is required for some zip proxy like PclZipProxy
if ( in_array ( $this -> config [ 'ZIP_PROXY' ], array ( 'PclZipProxy' )) && ! is_dir ( $this -> config [ 'PATH_TO_TMP' ])) {
throw new OdfException ( 'Temporary directory ' . $this -> config [ 'PATH_TO_TMP' ] . ' must exists' );
}
2010-05-12 19:15:02 +02:00
2013-04-20 11:03:23 +02:00
// Create tmp direcoty (will be deleted in destructor)
if ( ! file_exists ( $this -> tmpdir )) {
$result = mkdir ( $this -> tmpdir );
}
2010-02-28 23:49:06 +01:00
2013-04-20 11:03:23 +02:00
// Load zip proxy
$zipHandler = $this -> config [ 'ZIP_PROXY' ];
if ( ! defined ( 'PCLZIP_TEMPORARY_DIR' )) define ( 'PCLZIP_TEMPORARY_DIR' , $this -> tmpdir );
include_once ( 'zip/' . $zipHandler . '.php' );
if ( ! class_exists ( $this -> config [ 'ZIP_PROXY' ])) {
throw new OdfException ( $this -> config [ 'ZIP_PROXY' ] . ' class not found - check your php settings' );
}
$this -> file = new $zipHandler ( $this -> tmpdir );
2010-03-13 17:05:36 +01:00
2013-04-20 11:03:23 +02:00
if ( $this -> file -> open ( $filename ) !== true ) { // This also create the tmpdir directory
throw new OdfException ( " Error while Opening the file ' $filename ' - Check your odt filename " );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
if (( $this -> contentXml = $this -> file -> getFromName ( 'content.xml' )) === false ) {
throw new OdfException ( " Nothing to parse - Check that the content.xml file is correctly formed in source file ' $filename ' " );
}
if (( $this -> manifestXml = $this -> file -> getFromName ( 'META-INF/manifest.xml' )) === false ) {
throw new OdfException ( " Something is wrong with META-INF/manifest.xml in source file ' $filename ' " );
}
2015-09-05 00:43:13 +02:00
if (( $this -> metaXml = $this -> file -> getFromName ( 'meta.xml' )) === false ) {
throw new OdfException ( " Nothing to parse - Check that the meta.xml file is correctly formed in source file ' $filename ' " );
}
2013-04-20 11:03:23 +02:00
if (( $this -> stylesXml = $this -> file -> getFromName ( 'styles.xml' )) === false ) {
throw new OdfException ( " Nothing to parse - Check that the styles.xml file is correctly formed in source file ' $filename ' " );
}
$this -> file -> close ();
//print "tmpdir=".$tmpdir;
//print "filename=".$filename;
//print "tmpfile=".$tmpfile;
copy ( $filename , $this -> tmpfile );
2017-10-10 18:54:30 +02:00
// Now file has been loaded, we must move the [!-- BEGIN and [!-- END tags outside the
2016-06-22 20:22:22 +02:00
// <table:table-row tag and clean bad lines tags.
2013-04-20 11:03:23 +02:00
$this -> _moveRowSegments ();
}
/**
* Assing a template variable
*
2017-04-29 01:01:12 +02:00
* @ 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
2017-10-10 18:54:30 +02:00
* @ param string $charset Charset
2013-04-20 11:03:23 +02:00
* @ throws OdfException
* @ return odf
*/
public function setVars ( $key , $value , $encode = true , $charset = 'ISO-8859' )
{
$tag = $this -> config [ 'DELIMITER_LEFT' ] . $key . $this -> config [ 'DELIMITER_RIGHT' ];
// TODO Warning string may be:
// <text:span text:style-name="T13">{</text:span><text:span text:style-name="T12">aaa</text:span><text:span text:style-name="T13">}</text:span>
// instead of {aaa} so we should enhance this function.
//print $key.'-'.$value.'-'.strpos($this->contentXml, $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']).'<br>';
2017-04-29 01:01:12 +02:00
if ( strpos ( $this -> contentXml , $tag ) === false && strpos ( $this -> stylesXml , $tag ) === false ) {
2021-01-26 16:10:27 +01:00
// Add the throw only for development. In most cases, it is normal to not having the key into the document (only few keys are presents).
//throw new OdfException("var $key not found in the document");
2021-02-09 22:02:48 +01:00
return $this ;
2013-04-11 18:38:50 +02:00
}
2014-05-07 19:13:02 +02:00
2020-09-29 12:17:25 +02:00
$this -> vars [ $tag ] = $this -> convertVarToOdf ( $value , $encode , $charset );
2020-10-15 19:36:08 +02:00
2020-09-29 12:17:25 +02:00
return $this ;
}
/**
* Replaces html tags in odt tags and returns a compatible string
* @ 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
* @ return string
*/
public function convertVarToOdf ( $value , $encode = true , $charset = 'ISO-8859' )
{
2020-10-09 10:59:06 +02:00
$value = $encode ? htmlspecialchars ( $value ) : $value ;
2013-04-20 11:03:23 +02:00
$value = ( $charset == 'ISO-8859' ) ? utf8_encode ( $value ) : $value ;
2020-09-29 12:17:25 +02:00
$convertedValue = $value ;
2014-05-07 19:13:02 +02:00
2020-03-02 10:18:38 +01:00
// Check if the value includes html tags
2020-03-04 08:54:49 +01:00
if ( $this -> _hasHtmlTag ( $value ) === true ) {
// Default styles for strong/b, i/em, u, s, sub & sup
$automaticStyles = array (
'<style:style style:name="boldText" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>' ,
'<style:style style:name="italicText" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>' ,
'<style:style style:name="underlineText" style:family="text"><style:text-properties style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" /></style:style>' ,
'<style:style style:name="strikethroughText" style:family="text"><style:text-properties style:text-line-through-style="solid" style:text-line-through-type="single" /></style:style>' ,
'<style:style style:name="subText" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>' ,
'<style:style style:name="supText" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>'
);
2020-10-15 19:36:08 +02:00
2020-09-29 12:17:25 +02:00
$convertedValue = $this -> _replaceHtmlWithOdtTag ( $this -> _getDataFromHtml ( $value ), $customStyles , $fontDeclarations );
2020-10-15 19:36:08 +02:00
2020-03-04 08:54:49 +01:00
foreach ( $customStyles as $key => $val ) {
array_push ( $automaticStyles , '<style:style style:name="customStyle' . $key . '" style:family="text">' . $val . '</style:style>' );
}
2014-05-07 19:13:02 +02:00
2020-03-02 10:18:38 +01:00
// Join the styles and add them to the content xml
$styles = '' ;
2020-03-04 08:54:49 +01:00
foreach ( $automaticStyles as $style ) {
2020-03-02 10:18:38 +01:00
if ( strpos ( $this -> contentXml , $style ) === false ) {
$styles .= $style ;
}
}
$this -> contentXml = str_replace ( '</office:automatic-styles>' , $styles . '</office:automatic-styles>' , $this -> contentXml );
2020-03-04 08:54:49 +01:00
2020-03-03 10:19:05 +01:00
// Join the font declarations and add them to the content xml
$fonts = '' ;
2020-03-04 08:54:49 +01:00
foreach ( $fontDeclarations as $font ) {
2020-03-03 10:19:05 +01:00
if ( strpos ( $this -> contentXml , 'style:name="' . $font . '"' ) === false ) {
$fonts .= '<style:font-face style:name="' . $font . '" svg:font-family="\'' . $font . '\'" />' ;
}
}
$this -> contentXml = str_replace ( '</office:font-face-decls>' , $fonts . '</office:font-face-decls>' , $this -> contentXml );
2020-03-02 10:18:38 +01:00
}
2020-09-29 12:17:25 +02:00
else $convertedValue = preg_replace ( '/(\r\n|\r|\n)/i' , " <text:line-break/> " , $value );
return $convertedValue ;
2013-04-20 11:03:23 +02:00
}
2020-03-04 08:54:49 +01:00
/**
* Replaces html tags in with odt tags and returns an odt string
* @ param array $tags An array with html tags generated by the getDataFromHtml () function
* @ param array $customStyles An array of style defenitions that should be included inside the odt file
* @ param array $fontDeclarations An array of font declarations that should be included inside the odt file
* @ return string
*/
private function _replaceHtmlWithOdtTag ( $tags , & $customStyles , & $fontDeclarations )
{
if ( $customStyles == null ) $customStyles = array ();
if ( $fontDeclarations == null ) $fontDeclarations = array ();
$odtResult = '' ;
foreach (( array ) $tags as $tag ) {
// Check if the current item is a tag or just plain text
if ( isset ( $tag [ 'text' ])) {
$odtResult .= $tag [ 'text' ];
} elseif ( isset ( $tag [ 'name' ])) {
switch ( $tag [ 'name' ]) {
case 'br' :
$odtResult .= '<text:line-break/>' ;
break ;
case 'strong' :
case 'b' :
$odtResult .= '<text:span text:style-name="boldText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 'i' :
case 'em' :
$odtResult .= '<text:span text:style-name="italicText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 'u' :
$odtResult .= '<text:span text:style-name="underlineText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 's' :
$odtResult .= '<text:span text:style-name="strikethroughText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 'sub' :
$odtResult .= '<text:span text:style-name="subText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 'sup' :
$odtResult .= '<text:span text:style-name="supText">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
break ;
case 'span' :
if ( isset ( $tag [ 'attributes' ][ 'style' ])) {
$odtStyles = '' ;
foreach ( $tag [ 'attributes' ][ 'style' ] as $styleName => $styleValue ) {
switch ( $styleName ) {
case 'font-family' :
$fontName = $styleValue ;
if ( strpos ( $fontName , ',' ) !== false ) {
$fontName = explode ( ',' , $fontName )[ 0 ];
}
if ( ! in_array ( $fontName , $fontDeclarations )) {
array_push ( $fontDeclarations , $fontName );
}
$odtStyles .= '<style:text-properties style:font-name="' . $fontName . '" />' ;
break ;
case 'font-size' :
if ( preg_match ( '/([0-9]+)\s?(px|pt)/' , $styleValue , $matches )) {
$fontSize = intval ( $matches [ 1 ]);
if ( $matches [ 2 ] == 'px' ) {
$fontSize = round ( $fontSize * 0.75 );
}
$odtStyles .= '<style:text-properties fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt" />' ;
}
break ;
case 'color' :
if ( preg_match ( '/#[0-9A-Fa-f]{3}(?:[0-9A-Fa-f]{3})?/' , $styleValue )) {
$odtStyles .= '<style:text-properties fo:color="' . $styleValue . '" />' ;
}
break ;
}
}
if ( strlen ( $odtStyles ) > 0 ) {
// Generate a unique id for the style (using microtime and random because some CPUs are really fast...)
$key = floatval ( str_replace ( '.' , '' , microtime ( true ))) + rand ( 0 , 10 );
$customStyles [ $key ] = $odtStyles ;
$odtResult .= '<text:span text:style-name="customStyle' . $key . '">' . ( $tag [ 'children' ] != null ? $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations ) : $tag [ 'innerText' ]) . '</text:span>' ;
}
}
break ;
default :
$odtResult .= $this -> _replaceHtmlWithOdtTag ( $tag [ 'children' ], $customStyles , $fontDeclarations );
break ;
}
}
}
return $odtResult ;
}
/**
* Checks if the given text is a html string
* @ param string $text The text to check
* @ return bool
*/
private function _isHtmlTag ( $text )
{
return preg_match ( '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/' , $text );
}
/**
* Checks if the given text includes a html string
* @ param string $text The text to check
* @ return bool
*/
private function _hasHtmlTag ( $text )
{
$result = preg_match_all ( '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/' , $text );
return is_numeric ( $result ) && $result > 0 ;
}
/**
* Returns an array of html elements
* @ param string $html A string with html tags
* @ return array
*/
private function _getDataFromHtml ( $html )
{
$tags = array ();
$tempHtml = $html ;
while ( strlen ( $tempHtml ) > 0 ) {
// Check if the string includes a html tag
if ( preg_match_all ( '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/' , $tempHtml , $matches )) {
$tagOffset = strpos ( $tempHtml , $matches [ 0 ][ 0 ]);
// Check if the string starts with the html tag
if ( $tagOffset > 0 ) {
// Push the text infront of the html tag to the result array
array_push ( $tags , array (
'text' => substr ( $tempHtml , 0 , $tagOffset )
));
// Remove the text from the string
$tempHtml = substr ( $tempHtml , $tagOffset );
}
// Extract the attribute data from the html tag
2020-09-17 13:19:31 +02:00
preg_match_all ( '/([0-9A-Za-z]+(?:="[0-9A-Za-z\:\-\s\,\;\#]*")?)+/' , $matches [ 2 ][ 0 ], $explodedAttributes );
2020-03-04 08:54:49 +01:00
$explodedAttributes = array_filter ( $explodedAttributes [ 0 ]);
$attributes = array ();
// Store each attribute with its name in the $attributes array
$explodedAttributesCount = count ( $explodedAttributes );
for ( $i = 0 ; $i < $explodedAttributesCount ; $i ++ ) {
$attribute = trim ( $explodedAttributes [ $i ]);
// Check if the attribute has a value (like style="") or has no value (like required)
if ( strpos ( $attribute , '=' ) !== false ) {
$splitAttribute = explode ( '=' , $attribute );
$attrName = trim ( $splitAttribute [ 0 ]);
$attrValue = trim ( str_replace ( '"' , '' , $splitAttribute [ 1 ]));
// check if the current attribute is a style attribute
if ( strtolower ( $attrName ) == 'style' ) {
$attributes [ $attrName ] = array ();
if ( strpos ( $attrValue , ';' ) !== false ) {
// Split the style properties and store them in an array
$explodedStyles = explode ( ';' , $attrValue );
$explodedStylesCount = count ( $explodedStyles );
for ( $n = 0 ; $n < $explodedStylesCount ; $n ++ ) {
$splitStyle = explode ( ':' , $explodedStyles [ $n ]);
$attributes [ $attrName ][ trim ( $splitStyle [ 0 ])] = trim ( $splitStyle [ 1 ]);
}
} else {
$splitStyle = explode ( ':' , $attrValue );
$attributes [ $attrName ][ trim ( $splitStyle [ 0 ])] = trim ( $splitStyle [ 1 ]);
}
} else {
// Store the value directly in the $attributes array if this is not the style attribute
$attributes [ $attrName ] = $attrValue ;
}
} else {
$attributes [ trim ( $attribute )] = true ;
}
}
// Push the html tag data to the result array
array_push ( $tags , array (
'name' => $matches [ 1 ][ 0 ],
'attributes' => $attributes ,
'innerText' => strip_tags ( $matches [ 3 ][ 0 ]),
'children' => $this -> _hasHtmlTag ( $matches [ 3 ][ 0 ]) ? $this -> _getDataFromHtml ( $matches [ 3 ][ 0 ]) : null
));
// Remove the processed html tag from the html string
$tempHtml = substr ( $tempHtml , strlen ( $matches [ 0 ][ 0 ]));
} else {
array_push ( $tags , array (
'text' => $tempHtml
));
$tempHtml = '' ;
}
}
return $tags ;
}
2014-05-07 19:13:02 +02:00
/**
* Function to convert a HTML string into an ODT string
*
* @ param string $value String to convert
*/
public function htmlToUTFAndPreOdf ( $value )
{
// We decode into utf8, entities
2020-10-15 19:36:08 +02:00
$value = dol_html_entity_decode ( $value , ENT_QUOTES | ENT_HTML5 );
2014-05-07 19:13:02 +02:00
// We convert html tags
$ishtml = dol_textishtml ( $value );
if ( $ishtml )
{
// If string is "MYPODUCT - Desc <strong>bold</strong> with é accent<br />\n<br />\nUn texto en español ?"
// Result after clean must be "MYPODUCT - Desc bold with é accent\n\nUn texto en español ?"
// We want to ignore \n and we want all <br> to be \n
$value = preg_replace ( '/(\r\n|\r|\n)/i' , '' , $value );
$value = preg_replace ( '/<br>/i' , " \n " , $value );
$value = preg_replace ( '/<br\s+[^<>\/]*>/i' , " \n " , $value );
$value = preg_replace ( '/<br\s+[^<>\/]*\/>/i' , " \n " , $value );
//$value=preg_replace('/<strong>/','__lt__text:p text:style-name=__quot__bold__quot____gt__',$value);
//$value=preg_replace('/<\/strong>/','__lt__/text:p__gt__',$value);
$value = dol_string_nohtmltag ( $value , 0 );
}
return $value ;
}
/**
* Function to convert a HTML string into an ODT string
*
* @ param string $value String to convert
*/
public function preOdfToOdf ( $value )
{
$value = str_replace ( " \n " , " <text:line-break/> " , $value );
//$value = str_replace("__lt__", "<", $value);
//$value = str_replace("__gt__", ">", $value);
//$value = str_replace("__quot__", '"', $value);
return $value ;
}
2013-04-20 11:03:23 +02:00
/**
* Evaluating php codes inside the ODT and output the buffer ( print , echo ) inplace of the code
*
2015-09-05 00:43:13 +02:00
* @ return int 0
2013-04-20 11:03:23 +02:00
*/
public function phpEval ()
{
preg_match_all ( '/[\{\<]\?(php)?\s+(?P<content>.+)\?[\}\>]/iU' , $this -> contentXml , $matches ); // detecting all {?php code ?} or <?php code ? >
2016-06-22 20:08:29 +02:00
$nbfound = count ( $matches [ 'content' ]);
2017-10-10 18:54:30 +02:00
for ( $i = 0 ; $i < $nbfound ; $i ++ )
2016-06-22 20:08:29 +02:00
{
2013-04-20 11:03:23 +02:00
try {
2013-04-07 17:27:35 +02:00
$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
$code = $matches [ 'content' ][ $i ];
ob_start ();
eval ( $code );
$ob_output = ob_get_contents (); // send the content of the buffer into $ob_output
$this -> contentXml = str_replace ( $matches [ 0 ][ $i ], $ob_output , $this -> contentXml );
ob_end_clean ();
2013-04-20 11:03:23 +02:00
} catch ( Exception $e ) {
ob_end_clean ();
$this -> contentXml = str_replace ( $matches [ 0 ][ $i ], 'ERROR: there was a problem while evaluating this portion of code, please fix it: ' . $e , $this -> contentXml );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
}
return 0 ;
}
/**
* Assign a template variable as a picture
*
* @ param string $key name of the variable within the template
* @ param string $value path to the picture
* @ throws OdfException
* @ return odf
*/
public function setImage ( $key , $value )
{
$filename = strtok ( strrchr ( $value , '/' ), '/.' );
$file = substr ( strrchr ( $value , '/' ), 1 );
$size = @ getimagesize ( $value );
if ( $size === false ) {
throw new OdfException ( " Invalid image " );
}
list ( $width , $height ) = $size ;
$width *= self :: PIXEL_TO_CM ;
$height *= self :: PIXEL_TO_CM ;
$xml = <<< IMG
2013-04-07 17:27:35 +02:00
< draw : frame draw : style - name = " fr1 " draw : name = " $filename " text : anchor - type = " aschar " svg : width = " { $width } cm " svg : height = " { $height } cm " draw : z - index = " 3 " >< draw : image xlink : href = " Pictures/ $file " xlink : type = " simple " xlink : show = " embed " xlink : actuate = " onLoad " /></ draw : frame >
2010-02-15 23:39:13 +01:00
IMG ;
2013-04-20 11:03:23 +02:00
$this -> images [ $value ] = $file ;
$this -> setVars ( $key , $xml , false );
return $this ;
}
/**
* Move segment tags for lines of tables
2016-06-22 20:08:29 +02:00
* This function is called automatically within the constructor , so this -> contentXml is clean before any other thing
2013-04-20 11:03:23 +02:00
*
* @ return void
*/
private function _moveRowSegments ()
{
2016-06-22 20:08:29 +02:00
// Replace BEGIN<text:s/>xxx into BEGIN xxx
$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 );
2017-10-10 18:54:30 +02:00
2016-06-22 20:08:29 +02:00
// Search all possible rows in the document
2013-04-20 11:03:23 +02:00
$reg1 = " #<table:table-row[^>]*>(.*)</table:table-row>#smU " ;
preg_match_all ( $reg1 , $this -> contentXml , $matches );
for ( $i = 0 , $size = count ( $matches [ 0 ]); $i < $size ; $i ++ ) {
// Check if the current row contains a segment row.*
$reg2 = '#\[!--\sBEGIN\s(row.[\S]*)\s--\](.*)\[!--\sEND\s\\1\s--\]#sm' ;
if ( preg_match ( $reg2 , $matches [ 0 ][ $i ], $matches2 )) {
$balise = str_replace ( 'row.' , '' , $matches2 [ 1 ]);
// Move segment tags around the row
$replace = array (
'[!-- BEGIN ' . $matches2 [ 1 ] . ' --]' => '' ,
'[!-- END ' . $matches2 [ 1 ] . ' --]' => '' ,
'<table:table-row' => '[!-- BEGIN ' . $balise . ' --]<table:table-row' ,
'</table:table-row>' => '</table:table-row>[!-- END ' . $balise . ' --]'
);
$replacedXML = str_replace ( array_keys ( $replace ), array_values ( $replace ), $matches [ 0 ][ $i ]);
$this -> contentXml = str_replace ( $matches [ 0 ][ $i ], $replacedXML , $this -> contentXml );
}
}
}
/**
* Merge template variables
2016-07-29 16:24:02 +02:00
* Called at the beginning of the _save function
2013-04-20 11:03:23 +02:00
*
2015-09-05 00:43:13 +02:00
* @ param string $type 'content' , 'styles' or 'meta'
2013-04-20 11:03:23 +02:00
* @ return void
*/
private function _parse ( $type = 'content' )
{
2015-11-02 15:44:15 +01:00
// Search all tags fou into condition to complete $this->vars, so we will proceed all tests even if not defined
2015-11-12 09:24:04 +01:00
$reg = '@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU' ;
2015-11-02 15:44:15 +01:00
preg_match_all ( $reg , $this -> contentXml , $matches , PREG_SET_ORDER );
2017-10-10 18:54:30 +02:00
2015-11-02 15:44:15 +01:00
//var_dump($this->vars);exit;
foreach ( $matches as $match ) // For each match, if there is no entry into this->vars, we add it
{
if ( ! empty ( $match [ 1 ]) && ! isset ( $this -> vars [ $match [ 1 ]]))
{
$this -> vars [ $match [ 1 ]] = '' ; // Not defined, so we set it to '', we just need entry into this->vars for next loop
}
}
//var_dump($this->vars);exit;
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
// Conditionals substitution
2015-09-05 00:43:13 +02:00
// Note: must be done before static substitution, else the variable will be replaced by its value and the conditional won't work anymore
2015-11-02 15:44:15 +01:00
foreach ( $this -> vars as $key => $value )
2010-03-13 17:05:36 +01:00
{
2013-04-20 11:03:23 +02:00
// If value is true (not 0 nor false nor null nor empty string)
2015-11-02 15:44:15 +01:00
if ( $value )
2013-04-20 11:03:23 +02:00
{
2016-07-29 16:31:29 +02:00
//dol_syslog("Var ".$key." is defined, we remove the IF, ELSE and ENDIF ");
//$sav=$this->contentXml;
2013-04-20 11:03:23 +02:00
// Remove the IF tag
$this -> contentXml = str_replace ( '[!-- IF ' . $key . ' --]' , '' , $this -> contentXml );
// Remove everything between the ELSE tag (if it exists) and the ENDIF tag
$reg = '@(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU' ; // U modifier = all quantifiers are non-greedy
$this -> contentXml = preg_replace ( $reg , '' , $this -> contentXml );
2016-07-29 16:31:29 +02:00
/* if ( $sav != $this -> contentXml )
2016-07-29 16:24:02 +02:00
{
dol_syslog ( " We found a IF and it was processed " );
2016-07-29 16:31:29 +02:00
//var_dump($sav);exit;
} */
2013-04-20 11:03:23 +02:00
}
// Else the value is false, then two cases: no ELSE and we're done, or there is at least one place where there is an ELSE clause, then we replace it
else
{
2016-07-29 16:31:29 +02:00
//dol_syslog("Var ".$key." is not defined, we remove the IF, ELSE and ENDIF ");
//$sav=$this->contentXml;
2013-04-20 11:03:23 +02:00
// Find all conditional blocks for this variable: from IF to ELSE and to ENDIF
$reg = '@\[!--\sIF\s' . $key . '\s--\](.*)(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU' ; // U modifier = all quantifiers are non-greedy
preg_match_all ( $reg , $this -> contentXml , $matches , PREG_SET_ORDER );
foreach ( $matches as $match ) { // For each match, if there is an ELSE clause, we replace the whole block by the value in the ELSE clause
if ( ! empty ( $match [ 3 ])) $this -> contentXml = str_replace ( $match [ 0 ], $match [ 3 ], $this -> contentXml );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
// Cleanup the other conditional blocks (all the others where there were no ELSE clause, we can just remove them altogether)
$this -> contentXml = preg_replace ( $reg , '' , $this -> contentXml );
2016-07-29 16:31:29 +02:00
/* if ( $sav != $this -> contentXml )
2016-07-29 16:24:02 +02:00
{
dol_syslog ( " We found a IF and it was processed " );
//var_dump($sav);exit;
2016-07-29 16:31:29 +02:00
} */
2010-03-13 17:05:36 +01:00
}
}
2010-05-12 19:15:02 +02:00
2015-09-05 00:43:13 +02:00
// Static substitution
2013-04-20 11:03:23 +02:00
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 );
2015-09-05 00:43:13 +02:00
if ( $type == 'meta' ) $this -> metaXml = str_replace ( array_keys ( $this -> vars ), array_values ( $this -> vars ), $this -> metaXml );
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
}
/**
* Add the merged segment to the document
*
2016-06-22 20:08:29 +02:00
* @ param Segment $segment Segment
2013-04-20 11:03:23 +02:00
* @ throws OdfException
* @ return odf
*/
public function mergeSegment ( Segment $segment )
{
if ( ! array_key_exists ( $segment -> getName (), $this -> segments )) {
throw new OdfException ( $segment -> getName () . 'cannot be parsed, has it been set yet ?' );
}
$string = $segment -> getName ();
// $reg = '@<text:p[^>]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@smU';
$reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU' ;
$this -> contentXml = preg_replace ( $reg , $segment -> getXmlParsed (), $this -> contentXml );
return $this ;
}
/**
* Display all the current template variables
*
* @ return string
*/
public function printVars ()
{
return print_r ( '<pre>' . print_r ( $this -> vars , true ) . '</pre>' , true );
}
/**
* Display the XML content of the file from odt document
* as it is at the moment
*
* @ return string
*/
public function __toString ()
{
return $this -> contentXml ;
}
/**
* Display loop segments declared with setSegment ()
*
* @ return string
*/
public function printDeclaredSegments ()
{
return '<pre>' . print_r ( implode ( ' ' , array_keys ( $this -> segments )), true ) . '</pre>' ;
}
/**
2016-03-22 19:24:48 +01:00
* Declare a segment in order to use it in a loop .
* Extract the segment and store it into $this -> segments [] . Return it for next call .
2013-04-20 11:03:23 +02:00
*
2016-06-22 20:08:29 +02:00
* @ param string $segment Segment
2013-04-20 11:03:23 +02:00
* @ throws OdfException
* @ return Segment
*/
public function setSegment ( $segment )
{
if ( array_key_exists ( $segment , $this -> segments )) {
return $this -> segments [ $segment ];
}
// $reg = "#\[!--\sBEGIN\s$segment\s--\]<\/text:p>(.*)<text:p\s.*>\[!--\sEND\s$segment\s--\]#sm";
$reg = " # \ [!-- \ sBEGIN \ s $segment\s -- \ ](.*) \ [!-- \ sEND \ s $segment\s -- \ ]#sm " ;
if ( preg_match ( $reg , html_entity_decode ( $this -> contentXml ), $m ) == 0 ) {
2016-06-22 20:08:29 +02:00
throw new OdfException ( " ' " . $segment . " ' segment not found in the document. The tag [!-- BEGIN xxx --] or [!-- END xxx --] is not present into content file. " );
2013-04-20 11:03:23 +02:00
}
$this -> segments [ $segment ] = new Segment ( $segment , $m [ 1 ], $this );
return $this -> segments [ $segment ];
}
/**
* Save the odt file on the disk
*
* @ param string $file name of the desired file
* @ throws OdfException
* @ return void
*/
public function saveToDisk ( $file = null )
{
if ( $file !== null && is_string ( $file )) {
if ( file_exists ( $file ) && ! ( is_file ( $file ) && is_writable ( $file ))) {
throw new OdfException ( 'Permission denied : can\'t create ' . $file );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
$this -> _save ();
copy ( $this -> tmpfile , $file );
} else {
$this -> _save ();
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
}
/**
* Write output file onto disk
*
* @ throws OdfException
* @ return void
*/
private function _save ()
{
$res = $this -> file -> open ( $this -> tmpfile ); // tmpfile is odt template
$this -> _parse ( 'content' );
$this -> _parse ( 'styles' );
2015-09-05 00:43:13 +02:00
$this -> _parse ( 'meta' );
2013-04-20 11:03:23 +02:00
2015-09-05 00:43:13 +02:00
$this -> setMetaData ();
//print $this->metaXml;exit;
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
if ( ! $this -> file -> addFromString ( 'content.xml' , $this -> contentXml )) {
2015-09-05 00:43:13 +02:00
throw new OdfException ( 'Error during file export addFromString content' );
}
if ( ! $this -> file -> addFromString ( 'meta.xml' , $this -> metaXml )) {
throw new OdfException ( 'Error during file export addFromString meta' );
2013-04-20 11:03:23 +02:00
}
if ( ! $this -> file -> addFromString ( 'styles.xml' , $this -> stylesXml )) {
2015-09-05 00:43:13 +02:00
throw new OdfException ( 'Error during file export addFromString styles' );
2013-04-20 11:03:23 +02:00
}
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
foreach ( $this -> images as $imageKey => $imageValue ) {
// Add the image inside the ODT document
$this -> file -> addFile ( $imageKey , 'Pictures/' . $imageValue );
// Add the image to the Manifest (which maintains a list of images, necessary to avoid "Corrupt ODT file. Repair?" when opening the file with LibreOffice)
$this -> addImageToManifest ( $imageValue );
}
if ( ! $this -> file -> addFromString ( './META-INF/manifest.xml' , $this -> manifestXml )) {
throw new OdfException ( 'Error during file export: manifest.xml' );
}
$this -> file -> close ();
}
2015-09-05 00:43:13 +02:00
/**
* Update Meta information
* < dc : date > 2013 - 03 - 16 T14 : 06 : 25 </ dc : date >
*
* @ return void
*/
public function setMetaData ()
{
if ( empty ( $this -> creator )) $this -> creator = '' ;
2017-10-10 18:54:30 +02:00
2015-09-05 00:43:13 +02:00
$this -> metaXml = preg_replace ( '/<dc:date>.*<\/dc:date>/' , '<dc:date>' . gmdate ( " Y-m-d \T H: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 );
2017-10-10 18:54:30 +02:00
2015-09-05 00:43:13 +02:00
if ( count ( $this -> userdefined ))
{
foreach ( $this -> userdefined as $key => $val )
{
$this -> metaXml = preg_replace ( '<meta:user-defined meta:name="' . $key . '"/>' , '' , $this -> metaXml );
$this -> metaXml = preg_replace ( '/<meta:user-defined meta:name="' . $key . '">.*<\/meta:user-defined>/' , '' , $this -> metaXml );
$this -> metaXml = str_replace ( '</office:meta>' , '<meta:user-defined meta:name="' . $key . '">' . htmlspecialchars ( $val ) . '</meta:user-defined></office:meta>' , $this -> metaXml );
}
}
}
2017-10-10 18:54:30 +02:00
2013-04-20 11:03:23 +02:00
/**
* Update Manifest file according to added image files
*
* @ param string $file Image file to add into manifest content
2015-09-05 00:43:13 +02:00
* @ return void
2013-04-20 11:03:23 +02:00
*/
public function addImageToManifest ( $file )
{
// Get the file extension
2020-01-07 21:13:31 +01:00
$ext = substr ( strrchr ( $file , '.' ), 1 );
2013-04-20 11:03:23 +02:00
// Create the correct image XML entry to add to the manifest (this is necessary because ODT format requires that we keep a list of the images in the manifest.xml)
$add = ' <manifest:file-entry manifest:media-type="image/' . $ext . '" manifest:full-path="Pictures/' . $file . '"/>' . " \n " ;
// Append the image to the manifest
$this -> manifestXml = str_replace ( '</manifest:manifest>' , $add . '</manifest:manifest>' , $this -> manifestXml ); // we replace the manifest closing tag by the image XML entry + manifest closing tag (this results in appending the data, we do not overwrite anything)
}
/**
* Export the file as attached file by HTTP
*
* @ param string $name ( optional )
* @ throws OdfException
* @ return void
*/
2020-01-07 21:13:31 +01:00
public function exportAsAttachedFile ( $name = " " )
2013-04-20 11:03:23 +02:00
{
$this -> _save ();
if ( headers_sent ( $filename , $linenum )) {
throw new OdfException ( " headers already sent ( $filename at $linenum ) " );
2010-03-13 17:05:36 +01:00
}
2010-05-12 19:15:02 +02:00
2013-04-20 11:03:23 +02:00
if ( $name == " " )
2010-03-13 17:05:36 +01:00
{
2013-04-20 11:03:23 +02:00
$name = md5 ( uniqid ()) . " .odt " ;
2010-03-13 17:05:36 +01:00
}
2010-05-12 19:15:02 +02:00
2013-04-20 11:03:23 +02:00
header ( 'Content-type: application/vnd.oasis.opendocument.text' );
header ( 'Content-Disposition: attachment; filename="' . $name . '"' );
header ( 'Content-Length: ' . filesize ( $this -> tmpfile ));
readfile ( $this -> tmpfile );
}
/**
* Convert the ODT file to PDF and export the file as attached file by HTTP
* Note : you need to have JODConverter and OpenOffice or LibreOffice installed and executable on the same system as where this php script will be executed . You also need to chmod + x odt2pdf . sh
*
2018-02-15 13:15:21 +01:00
* @ param string $name Name of ODT file to generate before generating PDF
2013-04-20 11:03:23 +02:00
* @ throws OdfException
* @ return void
*/
public function exportAsAttachedPDF ( $name = " " )
{
global $conf ;
2014-05-07 19:13:02 +02:00
2017-10-10 18:54:30 +02:00
if ( $name == " " ) $name = " temp " . md5 ( uniqid ());
2013-04-20 11:03:23 +02:00
2013-04-22 15:50:26 +02:00
dol_syslog ( get_class ( $this ) . '::exportAsAttachedPDF $name=' . $name , LOG_DEBUG );
2013-04-20 11:03:23 +02:00
$this -> saveToDisk ( $name );
$execmethod = ( empty ( $conf -> global -> MAIN_EXEC_USE_POPEN ) ? 1 : 2 ); // 1 or 2
2017-10-10 18:54:30 +02:00
// Method 1 sometimes hang the server.
2014-05-07 19:13:02 +02:00
2018-02-15 13:15:21 +01:00
// Export to PDF using LibreOffice
2018-02-15 10:15:27 +01:00
if ( $conf -> global -> MAIN_ODT_AS_PDF == 'libreoffice' )
2015-02-22 16:01:01 +01:00
{
2021-01-26 16:33:47 +01:00
dol_mkdir ( $conf -> user -> dir_temp ); // We must be sure the directory exists and is writable
2021-01-26 16:49:54 +01:00
// We delete and recreate a subdir because the soffice may have change pemrissions on it
dol_delete_dir_recursive ( $conf -> user -> dir_temp . '/odtaspdf' );
dol_mkdir ( $conf -> user -> dir_temp . '/odtaspdf' );
2021-01-26 16:33:47 +01:00
2021-01-08 15:09:49 +01:00
// Install prerequisites: apt install soffice libreoffice-common libreoffice-writer
2018-02-15 14:38:21 +01:00
// using windows libreoffice that must be in path
// using linux/mac libreoffice that must be in path
// Note PHP Config "fastcgi.impersonate=0" must set to 0 - Default is 1
2021-01-26 16:40:57 +01:00
$command = 'soffice --headless -env:UserInstallation=file:\'' . $conf -> user -> dir_temp . '/odtaspdf\' --convert-to pdf --outdir ' . escapeshellarg ( dirname ( $name )) . " " . escapeshellarg ( $name );
2018-02-15 13:15:21 +01:00
}
elseif ( preg_match ( '/unoconv/' , $conf -> global -> MAIN_ODT_AS_PDF ))
2015-02-22 16:01:01 +01:00
{
2017-10-10 18:54:30 +02:00
// 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
2018-02-15 13:23:13 +01:00
// If it fails:
// - set shell of user to bash instead of nologin.
2017-10-10 18:54:30 +02:00
// - 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);
2015-02-22 16:01:01 +01:00
}
else
{
2021-01-08 15:09:16 +01:00
// deprecated old method using odt2pdf.sh (native, jodconverter, ...)
2018-02-15 13:15:21 +01:00
$tmpname = preg_replace ( '/\.odt/i' , '' , $name );
2014-05-07 19:13:02 +02:00
2017-10-10 18:54:30 +02:00
if ( ! empty ( $conf -> global -> MAIN_DOL_SCRIPTS_ROOT ))
{
2018-02-15 13:15:21 +01:00
$command = $conf -> global -> MAIN_DOL_SCRIPTS_ROOT . '/scripts/odt2pdf/odt2pdf.sh ' . escapeshellcmd ( $tmpname ) . ' ' . ( is_numeric ( $conf -> global -> MAIN_ODT_AS_PDF ) ? 'jodconverter' : $conf -> global -> MAIN_ODT_AS_PDF );
2017-10-10 18:54:30 +02:00
}
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 );
2018-02-15 13:15:21 +01:00
$command = '../../scripts/odt2pdf/odt2pdf.sh ' . escapeshellcmd ( $tmpname ) . ' ' . ( is_numeric ( $conf -> global -> MAIN_ODT_AS_PDF ) ? 'jodconverter' : $conf -> global -> MAIN_ODT_AS_PDF );
2018-02-15 10:15:27 +01:00
}
2017-10-10 18:54:30 +02:00
}
2014-05-07 19:13:02 +02:00
2013-04-22 15:50:26 +02:00
//$dirname=dirname($name);
//$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname;
2017-10-10 18:54:30 +02:00
2013-04-22 12:08:35 +02:00
dol_syslog ( get_class ( $this ) . '::exportAsAttachedPDF $execmethod=' . $execmethod . ' Run command=' . $command , LOG_DEBUG );
2019-04-27 17:31:14 +02:00
$retval = 0 ; $output_arr = array ();
2013-04-20 11:03:23 +02:00
if ( $execmethod == 1 )
2010-03-13 17:05:36 +01:00
{
2013-04-20 11:03:23 +02:00
exec ( $command , $output_arr , $retval );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
if ( $execmethod == 2 )
2010-03-13 17:05:36 +01:00
{
2017-10-10 18:54:30 +02:00
$outputfile = DOL_DATA_ROOT . '/odt2pdf.log' ;
2018-02-15 10:15:27 +01:00
2013-04-20 11:03:23 +02:00
$ok = 0 ;
$handle = fopen ( $outputfile , 'w' );
if ( $handle )
{
2013-04-22 15:50:26 +02:00
dol_syslog ( get_class ( $this ) . " Run command " . $command , LOG_DEBUG );
2017-10-10 18:54:30 +02:00
fwrite ( $handle , $command . " \n " );
2013-04-20 11:03:23 +02:00
$handlein = popen ( $command , 'r' );
while ( ! feof ( $handlein ))
{
$read = fgets ( $handlein );
2017-10-10 18:54:30 +02:00
fwrite ( $handle , $read );
2013-04-20 11:03:23 +02:00
$output_arr [] = $read ;
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
pclose ( $handlein );
fclose ( $handle );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
if ( ! empty ( $conf -> global -> MAIN_UMASK )) @ chmod ( $outputfile , octdec ( $conf -> global -> MAIN_UMASK ));
2010-03-13 17:05:36 +01:00
}
2010-05-12 19:15:02 +02:00
2017-10-10 18:54:30 +02:00
if ( $retval == 0 )
2010-05-12 19:15:02 +02:00
{
2013-04-22 12:08:35 +02:00
dol_syslog ( get_class ( $this ) . '::exportAsAttachedPDF $ret_val=' . $retval , LOG_DEBUG );
2019-04-27 17:31:14 +02:00
$filename = '' ; $linenum = 0 ;
2010-03-13 17:05:36 +01:00
2021-03-02 01:58:36 +01:00
if ( php_sapi_name () != 'cli' ) { // If we are in a web context (not into CLI context)
if ( headers_sent ( $filename , $linenum )) {
throw new OdfException ( " headers already sent ( $filename at $linenum ) " );
}
if ( ! empty ( $conf -> global -> MAIN_DISABLE_PDF_AUTOUPDATE )) {
$name = preg_replace ( '/\.od(x|t)/i' , '' , $name );
header ( 'Content-type: application/pdf' );
header ( 'Content-Disposition: attachment; filename="' . $name . '.pdf"' );
readfile ( $name . " .pdf " );
}
2013-04-22 15:50:26 +02:00
}
2021-03-02 01:58:36 +01:00
2014-01-06 19:27:12 +01:00
if ( ! empty ( $conf -> global -> MAIN_ODT_AS_PDF_DEL_SOURCE ))
2018-02-15 13:15:21 +01:00
{
unlink ( $name );
}
2013-04-20 11:03:23 +02:00
} else {
2013-04-22 15:50:26 +02:00
dol_syslog ( get_class ( $this ) . '::exportAsAttachedPDF $ret_val=' . $retval , LOG_DEBUG );
2019-04-27 17:31:14 +02:00
dol_syslog ( get_class ( $this ) . '::exportAsAttachedPDF $output_arr=' . var_export ( $output_arr , true ), LOG_DEBUG );
2014-05-07 19:13:02 +02:00
2021-03-02 01:58:36 +01:00
if ( $retval == 126 ) {
2013-04-22 15:50:26 +02:00
throw new OdfException ( 'Permission execute convert script : ' . $command );
}
else {
2019-04-27 17:31:14 +02:00
$errorstring = '' ;
2013-04-22 15:50:26 +02:00
foreach ( $output_arr as $line ) {
2019-04-27 17:31:14 +02:00
$errorstring .= $line . " <br> " ;
2013-04-22 15:50:26 +02:00
}
2019-04-27 17:31:14 +02:00
throw new OdfException ( 'ODT to PDF convert fail (option MAIN_ODT_AS_PDF is ' . $conf -> global -> MAIN_ODT_AS_PDF . ', command was ' . $command . ', retval=' . $retval . ') : ' . $errorstring );
2013-04-22 15:50:26 +02:00
}
2010-02-15 23:39:13 +01:00
}
2013-04-20 11:03:23 +02:00
}
/**
* Returns a variable of configuration
*
2017-04-29 01:01:12 +02:00
* @ param string $configKey Config key
* @ return string The requested variable of configuration
2013-04-20 11:03:23 +02:00
*/
public function getConfig ( $configKey )
{
if ( array_key_exists ( $configKey , $this -> config )) {
return $this -> config [ $configKey ];
}
return false ;
}
/**
* Returns the temporary working file
*
* @ return string le chemin vers le fichier temporaire de travail
*/
public function getTmpfile ()
{
return $this -> tmpfile ;
}
/**
* Delete the temporary file when the object is destroyed
*/
public function __destruct ()
{
if ( file_exists ( $this -> tmpfile )) {
unlink ( $this -> tmpfile );
2010-03-13 17:05:36 +01:00
}
2010-02-28 23:49:06 +01:00
2013-04-20 11:03:23 +02:00
if ( file_exists ( $this -> tmpdir )) {
$this -> _rrmdir ( $this -> tmpdir );
rmdir ( $this -> tmpdir );
}
}
/**
* Empty the temporary working directory recursively
2017-10-10 18:54:30 +02:00
*
2017-04-29 01:01:12 +02:00
* @ param string $dir The temporary working directory
2013-04-20 11:03:23 +02:00
* @ return void
*/
private function _rrmdir ( $dir )
{
if ( $handle = opendir ( $dir )) {
2019-06-18 20:15:04 +02:00
while (( $file = readdir ( $handle )) !== false ) {
2013-04-20 11:03:23 +02:00
if ( $file != '.' && $file != '..' ) {
if ( is_dir ( $dir . '/' . $file )) {
$this -> _rrmdir ( $dir . '/' . $file );
rmdir ( $dir . '/' . $file );
} else {
unlink ( $dir . '/' . $file );
2010-03-13 17:05:36 +01:00
}
}
}
2013-04-20 11:03:23 +02:00
closedir ( $handle );
2010-03-13 17:05:36 +01:00
}
2013-04-20 11:03:23 +02:00
}
2014-11-01 21:00:28 +01:00
/**
* return the value present on odt in [ valuename ][ / valuename ]
2017-10-10 18:54:30 +02:00
*
2017-04-29 01:01:12 +02:00
* @ param string $valuename Balise in the template
* @ return string The value inside the balise
2014-11-01 21:00:28 +01:00
*/
public function getvalue ( $valuename )
{
$searchreg = " / \\ [ " . $valuename . " \\ ](.*) \\ [ \\ / " . $valuename . " \\ ]/ " ;
2015-02-22 16:01:01 +01:00
preg_match ( $searchreg , $this -> contentXml , $matches );
2014-11-01 21:00:28 +01:00
$this -> contentXml = preg_replace ( $searchreg , " " , $this -> contentXml );
return $matches [ 1 ];
}
2010-02-15 23:39:13 +01:00
}