This commit is contained in:
Laurent Destailleur 2021-07-05 23:07:40 +02:00
commit 2a5699a9a2
14 changed files with 356 additions and 355 deletions

View File

@ -1029,10 +1029,11 @@ function dol_size($size, $type = '')
/** /**
* Clean a string to use it as a file name * Clean a string to use it as a file name.
* Replace also '--' and ' -' strings, they are used for parameters separation.
* *
* @param string $str String to clean * @param string $str String to clean
* @param string $newstr String to replace bad chars with * @param string $newstr String to replace bad chars with.
* @param int $unaccent 1=Remove also accent (default), 0 do not remove them * @param int $unaccent 1=Remove also accent (default), 0 do not remove them
* @return string String cleaned (a-zA-Z_) * @return string String cleaned (a-zA-Z_)
* *
@ -1044,8 +1045,11 @@ function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
// Char '>' '<' '|' '$' and ';' are special chars for shells. // Char '>' '<' '|' '$' and ';' are special chars for shells.
// Char '/' and '\' are file delimiters. // Char '/' and '\' are file delimiters.
// -- car can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command // -- car can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
$filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '--'); $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';');
return dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars); $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
$tmp = preg_replace('/\-\-+/', '_', $tmp);
$tmp = preg_replace('/\s+\-/', ' _', $tmp);
return $tmp;
} }
/** /**
@ -1157,21 +1161,26 @@ function dol_string_unaccent($str)
* Clean a string from all punctuation characters to use it as a ref or login. * Clean a string from all punctuation characters to use it as a ref or login.
* This is a more complete function than dol_sanitizeFileName. * This is a more complete function than dol_sanitizeFileName.
* *
* @param string $str String to clean * @param string $str String to clean
* @param string $newstr String to replace forbidden chars with * @param string $newstr String to replace forbidden chars with
* @param array $badcharstoreplace List of forbidden characters * @param array|string $badcharstoreplace List of forbidden characters to replace
* @return string Cleaned string * @param array|string $badcharstoremove List of forbidden characters to remove
* @return string Cleaned string
* *
* @see dol_sanitizeFilename(), dol_string_unaccent(), dol_string_nounprintableascii() * @see dol_sanitizeFilename(), dol_string_unaccent(), dol_string_nounprintableascii()
*/ */
function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '') function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '')
{ {
$forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°'); // more complete than dol_sanitizeFileName $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°'); // more complete than dol_sanitizeFileName
$forbidden_chars_to_remove = array(); $forbidden_chars_to_remove = array();
//$forbidden_chars_to_remove=array("(",")");
if (is_array($badcharstoreplace)) { if (is_array($badcharstoreplace)) {
$forbidden_chars_to_replace = $badcharstoreplace; $forbidden_chars_to_replace = $badcharstoreplace;
} }
//$forbidden_chars_to_remove=array("(",")"); if (is_array($badcharstoremove)) {
$forbidden_chars_to_remove = $badcharstoremove;
}
return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str)); return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
} }
@ -7439,7 +7448,7 @@ function print_date_range($date_start, $date_end, $format = '', $outputlangs = '
* @param int $date_end End date * @param int $date_end End date
* @param string $format Output format * @param string $format Output format
* @param Translate $outputlangs Output language * @param Translate $outputlangs Output language
* @param integer $withparenthesis 1=Add parenthesis, 0=non parenthesis * @param integer $withparenthesis 1=Add parenthesis, 0=no parenthesis
* @return string String * @return string String
*/ */
function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1) function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
@ -8091,7 +8100,7 @@ function picto_from_langcode($codelang, $moreatt = '')
} }
if ($codelang == 'auto') { if ($codelang == 'auto') {
return '<span class="fa fa-globe"></span>'; return '<span class="fa fa-language"></span>';
} }
$langtocountryflag = array( $langtocountryflag = array(

View File

@ -356,7 +356,7 @@ if (!empty($conf->global->MAIN_EASTER_EGG_COMMITSTRIP)) {
<?php if ($main_home) { <?php if ($main_home) {
?> ?>
<div class="center login_main_home paddingtopbottom <?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent'; ?>" style="max-width: 70%"> <div class="center login_main_home paddingtopbottom <?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow'; ?>" style="max-width: 70%">
<?php echo $main_home; ?> <?php echo $main_home; ?>
</div><br> </div><br>
<?php <?php

View File

@ -216,7 +216,7 @@ if (!empty($morelogincontent)) {
</form> </form>
<div class="center login_main_home divpasswordmessagedesc paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent'; ?>" style="max-width: 70%"> <div class="center login_main_home divpasswordmessagedesc paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow'; ?>" style="max-width: 70%">
<?php if ($mode == 'dolibarr' || !$disabled) { ?> <?php if ($mode == 'dolibarr' || !$disabled) { ?>
<span class="passwordmessagedesc"> <span class="passwordmessagedesc">
<?php echo $langs->trans('SendNewPasswordDesc'); ?> <?php echo $langs->trans('SendNewPasswordDesc'); ?>

View File

@ -1084,7 +1084,7 @@ if (empty($reshook)) {
$fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int'); $fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int');
$qty = GETPOST('qty', 'int'); $qty = price2num(GETPOST('qty', 'alpha'));
if (empty($qty)) { if (empty($qty)) {
$qty = 1; $qty = 1;
} }
@ -1101,21 +1101,21 @@ if (empty($reshook)) {
$action = ''; $action = '';
} }
// Si aucune date n'est rentrée // If no date entered
if (empty($date) || $date == "--") { if (empty($date) || $date == "--") {
$error++; $error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors'); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
} elseif ($date < $object->date_debut || $date > ($object->date_fin + (24 * 3600 - 1))) {
// Warning if date out of range
$langs->load("errors");
setEventMessages($langs->trans("WarningDateOfLineMustBeInExpenseReportRange"), null, 'warnings');
} }
// Si aucun prix n'est rentré
// If no price entered
if ($value_unit == 0) { if ($value_unit == 0) {
$error++; $error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PriceUTTC")), null, 'errors'); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PriceUTTC")), null, 'errors');
} }
// Warning if date out of range
if ($date < $object->date_debut || $date > ($object->date_fin + (24 * 3600 - 1))) {
$langs->load("errors");
setEventMessages($langs->trans("WarningDateOfLineMustBeInExpenseReportRange"), null, 'warnings');
}
if (!$error) { if (!$error) {
$type = 0; // TODO What if service ? We should take the type product/service from the type of expense report llx_c_type_fees $type = 0; // TODO What if service ? We should take the type product/service from the type of expense report llx_c_type_fees
@ -1215,12 +1215,12 @@ if (empty($reshook)) {
} }
} }
$rowid = $_POST['rowid']; $rowid = GETPOST('rowid', 'int');
$type_fees_id = GETPOST('fk_c_type_fees', 'int'); $type_fees_id = GETPOST('fk_c_type_fees', 'int');
$fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int'); $fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int');
$projet_id = $fk_project; $projet_id = $fk_project;
$comments = GETPOST('comments', 'restricthtml'); $comments = GETPOST('comments', 'restricthtml');
$qty = GETPOST('qty', 'int'); $qty = price2num(GETPOST('qty', 'alpha'));
$vatrate = GETPOST('vatrate', 'alpha'); $vatrate = GETPOST('vatrate', 'alpha');
// if VAT is not used in Dolibarr, set VAT rate to 0 because VAT rate is necessary. // if VAT is not used in Dolibarr, set VAT rate to 0 because VAT rate is necessary.
@ -2474,32 +2474,32 @@ if ($action == 'create') {
print '</tr>'; print '</tr>';
} // Fin si c'est payé/validé } // Fin si c'est payé/validé
print '</table>'; print '</table>';
print '</div>'; print '</div>';
print '<script javascript> print '<script javascript>
/* JQuery for product free or predefined select */ /* JQuery for product free or predefined select */
jQuery(document).ready(function() { jQuery(document).ready(function() {
jQuery("#value_unit_ht").keyup(function(event) { jQuery("#value_unit_ht").keyup(function(event) {
console.log(event.which); // discard event tag and arrows console.log(event.which); // discard event tag and arrows
if (event.which != 9 && (event.which < 37 ||event.which > 40) && jQuery("#value_unit_ht").val() != "") { if (event.which != 9 && (event.which < 37 ||event.which > 40) && jQuery("#value_unit_ht").val() != "") {
jQuery("#value_unit").val(""); jQuery("#value_unit").val("");
} }
});
jQuery("#value_unit").keyup(function(event) {
console.log(event.which); // discard event tag and arrows
if (event.which != 9 && (event.which < 37 || event.which > 40) && jQuery("#value_unit").val() != "") {
jQuery("#value_unit_ht").val("");
}
});
}); });
jQuery("#value_unit").keyup(function(event) {
console.log(event.which); // discard event tag and arrows
if (event.which != 9 && (event.which < 37 || event.which > 40) && jQuery("#value_unit").val() != "") {
jQuery("#value_unit_ht").val("");
}
});
});
</script>'; </script>';
print '</form>'; print '</form>';
print dol_get_fiche_end(); print dol_get_fiche_end();
} }
} else { } else {
dol_print_error($db); dol_print_error($db);
@ -2511,9 +2511,11 @@ if ($action == 'create') {
exit(1); exit(1);
} }
/* /*
* Action bar * Action bar
*/ */
print '<div class="tabsAction">'; print '<div class="tabsAction">';
if ($action != 'create' && $action != 'edit') { if ($action != 'create' && $action != 'edit') {

View File

@ -2119,7 +2119,7 @@ class ExpenseReport extends CommonObject
$this->line->fk_ecm_files = $fk_ecm_files; $this->line->fk_ecm_files = $fk_ecm_files;
$this->line->id = $rowid; $this->line->id = ((int) $rowid);
// Select des infos sur le type fees // Select des infos sur le type fees
$sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees"; $sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees";
@ -2703,10 +2703,10 @@ class ExpenseReportLine
$sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',"; $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
$sql .= " '".$this->db->escape($this->comments)."',"; $sql .= " '".$this->db->escape($this->comments)."',";
$sql .= " ".((float) $this->qty).","; $sql .= " ".((float) $this->qty).",";
$sql .= " ".((int) $this->value_unit).","; $sql .= " ".((float) $this->value_unit).",";
$sql .= " ".price2num($this->total_ht).","; $sql .= " ".((float) price2num($this->total_ht)).",";
$sql .= " ".price2num($this->total_tva).","; $sql .= " ".((float) price2num($this->total_tva)).",";
$sql .= " ".price2num($this->total_ttc).","; $sql .= " ".((float) price2num($this->total_ttc)).",";
$sql .= " '".$this->db->idate($this->date)."',"; $sql .= " '".$this->db->idate($this->date)."',";
$sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").","; $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
$sql .= " ".((int) $this->fk_c_exp_tax_cat).","; $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
@ -2811,26 +2811,26 @@ class ExpenseReportLine
// Update line in database // Update line in database
$sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET"; $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
$sql .= " comments='".$this->db->escape($this->comments)."'"; $sql .= " comments='".$this->db->escape($this->comments)."'";
$sql .= ",value_unit = ".((float) $this->value_unit); $sql .= ", value_unit = ".((float) $this->value_unit);
$sql .= ",qty=".((float) $this->qty); $sql .= ", qty=".((float) $this->qty);
$sql .= ",date='".$this->db->idate($this->date)."'"; $sql .= ", date='".$this->db->idate($this->date)."'";
$sql .= ",total_ht=".((float) price2num($this->total_ht, 'MT')).""; $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'))."";
$sql .= ",total_tva=".((float) price2num($this->total_tva, 'MT')).""; $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'))."";
$sql .= ",total_ttc=".((float) price2num($this->total_ttc, 'MT')).""; $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'))."";
$sql .= ",tva_tx=".((float) $this->vatrate); $sql .= ", tva_tx=".((float) $this->vatrate);
$sql .= ",vat_src_code='".$this->db->escape($this->vat_src_code)."'"; $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
$sql .= ",rule_warning_message='".$this->db->escape($this->rule_warning_message)."'"; $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
$sql .= ",fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat); $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
$sql .= ",fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null'); $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
if ($this->fk_c_type_fees) { if ($this->fk_c_type_fees) {
$sql .= ",fk_c_type_fees = ".((int) $this->fk_c_type_fees); $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
} else { } else {
$sql .= ",fk_c_type_fees=null"; $sql .= ", fk_c_type_fees=null";
} }
if ($this->fk_project > 0) { if ($this->fk_project > 0) {
$sql .= ",fk_projet=".((int) $this->fk_project); $sql .= ", fk_projet=".((int) $this->fk_project);
} else { } else {
$sql .= ",fk_projet=null"; $sql .= ", fk_projet=null";
} }
$sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id)); $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));

View File

@ -72,7 +72,7 @@ if (empty($conf->global->EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES)) {
} }
// If the preview file is found // If the preview file is found
if (file_exists($fileimage)) { if (file_exists($fileimage)) {
$thumbshown = '<img height="'.$heightforphotref.'" class="photo photowithmargin photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">'; $thumbshown = '<img height="'.$heightforphotref.'" class="photo photowithmargin photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.urlencode($modulepart).'&file='.urlencode($relativepathimage).'">';
} }
} }
} }

View File

@ -65,12 +65,12 @@ class Odf
} }
$md5uniqid = md5(uniqid()); $md5uniqid = md5(uniqid());
if ($this->config['PATH_TO_TMP']) $this->tmpdir = preg_replace('|[\/]$|','',$this->config['PATH_TO_TMP']); // Remove last \ or / if ($this->config['PATH_TO_TMP']) $this->tmpdir = preg_replace('|[\/]$|', '', $this->config['PATH_TO_TMP']); // Remove last \ or /
$this->tmpdir .= ($this->tmpdir?'/':'').$md5uniqid; $this->tmpdir .= ($this->tmpdir?'/':'').$md5uniqid;
$this->tmpfile = $this->tmpdir.'/'.$md5uniqid.'.odt'; // We keep .odt extension to allow OpenOffice usage during debug. $this->tmpfile = $this->tmpdir.'/'.$md5uniqid.'.odt'; // We keep .odt extension to allow OpenOffice usage during debug.
// A working directory is required for some zip proxy like PclZipProxy // 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'])) { 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'); throw new OdfException('Temporary directory '.$this->config['PATH_TO_TMP'].' must exists');
} }
@ -81,8 +81,8 @@ class Odf
// Load zip proxy // Load zip proxy
$zipHandler = $this->config['ZIP_PROXY']; $zipHandler = $this->config['ZIP_PROXY'];
if (!defined('PCLZIP_TEMPORARY_DIR')) define('PCLZIP_TEMPORARY_DIR',$this->tmpdir); if (!defined('PCLZIP_TEMPORARY_DIR')) define('PCLZIP_TEMPORARY_DIR', $this->tmpdir);
include_once('zip/'.$zipHandler.'.php'); include_once 'zip/'.$zipHandler.'.php';
if (! class_exists($this->config['ZIP_PROXY'])) { if (! class_exists($this->config['ZIP_PROXY'])) {
throw new OdfException($this->config['ZIP_PROXY'] . ' class not found - check your php settings'); throw new OdfException($this->config['ZIP_PROXY'] . ' class not found - check your php settings');
} }
@ -147,13 +147,13 @@ class Odf
} }
/** /**
* Replaces html tags in odt tags and returns a compatible string * Replaces html tags in odt tags and returns a compatible string
* @param string $key Name of the variable within the template * @param string $key Name of the variable within the template
* @param string $value Replacement value * @param string $value Replacement value
* @param bool $encode If true, special XML characters are encoded * @param bool $encode If true, special XML characters are encoded
* @param string $charset Charset * @param string $charset Charset
* @return string * @return string
*/ */
public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859') public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859')
{ {
$value = $encode ? htmlspecialchars($value) : $value; $value = $encode ? htmlspecialchars($value) : $value;
@ -195,201 +195,200 @@ class Odf
} }
} }
$this->contentXml = str_replace('</office:font-face-decls>', $fonts . '</office:font-face-decls>', $this->contentXml); $this->contentXml = str_replace('</office:font-face-decls>', $fonts . '</office:font-face-decls>', $this->contentXml);
} } else $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $value);
else $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $value);
return $convertedValue; return $convertedValue;
} }
/** /**
* Replaces html tags in with odt tags and returns an odt string * 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 $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 $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 * @param array $fontDeclarations An array of font declarations that should be included inside the odt file
* @return string * @return string
*/ */
private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations) private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations)
{ {
if ($customStyles == null) $customStyles = array(); if ($customStyles == null) $customStyles = array();
if ($fontDeclarations == null) $fontDeclarations = array(); if ($fontDeclarations == null) $fontDeclarations = array();
$odtResult = ''; $odtResult = '';
foreach ((array) $tags as $tag) { foreach ((array) $tags as $tag) {
// Check if the current item is a tag or just plain text // Check if the current item is a tag or just plain text
if (isset($tag['text'])) { if (isset($tag['text'])) {
$odtResult .= $tag['text']; $odtResult .= $tag['text'];
} elseif (isset($tag['name'])) { } elseif (isset($tag['name'])) {
switch ($tag['name']) { switch ($tag['name']) {
case 'br': case 'br':
$odtResult .= '<text:line-break/>'; $odtResult .= '<text:line-break/>';
break; break;
case 'strong': case 'strong':
case 'b': case 'b':
$odtResult .= '<text:span text:style-name="boldText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="boldText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 'i': case 'i':
case 'em': case 'em':
$odtResult .= '<text:span text:style-name="italicText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="italicText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 'u': case 'u':
$odtResult .= '<text:span text:style-name="underlineText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="underlineText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 's': case 's':
$odtResult .= '<text:span text:style-name="strikethroughText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="strikethroughText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 'sub': case 'sub':
$odtResult .= '<text:span text:style-name="subText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="subText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 'sup': case 'sup':
$odtResult .= '<text:span text:style-name="supText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="supText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
break; break;
case 'span': case 'span':
if (isset($tag['attributes']['style'])) { if (isset($tag['attributes']['style'])) {
$odtStyles = ''; $odtStyles = '';
foreach ($tag['attributes']['style'] as $styleName => $styleValue) { foreach ($tag['attributes']['style'] as $styleName => $styleValue) {
switch ($styleName) { switch ($styleName) {
case 'font-family': case 'font-family':
$fontName = $styleValue; $fontName = $styleValue;
if (strpos($fontName, ',') !== false) { if (strpos($fontName, ',') !== false) {
$fontName = explode(',', $fontName)[0]; $fontName = explode(',', $fontName)[0];
} }
if (!in_array($fontName, $fontDeclarations)) { if (!in_array($fontName, $fontDeclarations)) {
array_push($fontDeclarations, $fontName); array_push($fontDeclarations, $fontName);
} }
$odtStyles .= '<style:text-properties style:font-name="' . $fontName . '" />'; $odtStyles .= '<style:text-properties style:font-name="' . $fontName . '" />';
break; break;
case 'font-size': case 'font-size':
if (preg_match('/([0-9]+)\s?(px|pt)/', $styleValue, $matches)) { if (preg_match('/([0-9]+)\s?(px|pt)/', $styleValue, $matches)) {
$fontSize = intval($matches[1]); $fontSize = intval($matches[1]);
if ($matches[2] == 'px') { if ($matches[2] == 'px') {
$fontSize = round($fontSize * 0.75); $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" />'; $odtStyles .= '<style:text-properties fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt" />';
} }
break; break;
case 'color': case 'color':
if (preg_match('/#[0-9A-Fa-f]{3}(?:[0-9A-Fa-f]{3})?/', $styleValue)) { if (preg_match('/#[0-9A-Fa-f]{3}(?:[0-9A-Fa-f]{3})?/', $styleValue)) {
$odtStyles .= '<style:text-properties fo:color="' . $styleValue . '" />'; $odtStyles .= '<style:text-properties fo:color="' . $styleValue . '" />';
} }
break; break;
} }
} }
if (strlen($odtStyles) > 0) { if (strlen($odtStyles) > 0) {
// Generate a unique id for the style (using microtime and random because some CPUs are really fast...) // 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); $key = floatval(str_replace('.', '', microtime(true)))+rand(0, 10);
$customStyles[$key] = $odtStyles; $customStyles[$key] = $odtStyles;
$odtResult .= '<text:span text:style-name="customStyle' . $key . '">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="customStyle' . $key . '">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>';
} }
} }
break; break;
default: default:
$odtResult .= $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations); $odtResult .= $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations);
break; break;
} }
} }
} }
return $odtResult; return $odtResult;
} }
/** /**
* Checks if the given text is a html string * Checks if the given text is a html string
* @param string $text The text to check * @param string $text The text to check
* @return bool * @return bool
*/ */
private function _isHtmlTag($text) private function _isHtmlTag($text)
{ {
return preg_match('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $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 * Checks if the given text includes a html string
* @param string $text The text to check * @param string $text The text to check
* @return bool * @return bool
*/ */
private function _hasHtmlTag($text) private function _hasHtmlTag($text)
{ {
$result = preg_match_all('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $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; return is_numeric($result) && $result > 0;
} }
/** /**
* Returns an array of html elements * Returns an array of html elements
* @param string $html A string with html tags * @param string $html A string with html tags
* @return array * @return array
*/ */
private function _getDataFromHtml($html) private function _getDataFromHtml($html)
{ {
$tags = array(); $tags = array();
$tempHtml = $html; $tempHtml = $html;
while (strlen($tempHtml) > 0) { while (strlen($tempHtml) > 0) {
// Check if the string includes a html tag // 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)) { 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]); $tagOffset = strpos($tempHtml, $matches[0][0]);
// Check if the string starts with the html tag // Check if the string starts with the html tag
if ($tagOffset > 0) { if ($tagOffset > 0) {
// Push the text infront of the html tag to the result array // Push the text infront of the html tag to the result array
array_push($tags, array( array_push($tags, array(
'text' => substr($tempHtml, 0, $tagOffset) 'text' => substr($tempHtml, 0, $tagOffset)
)); ));
// Remove the text from the string // Remove the text from the string
$tempHtml = substr($tempHtml, $tagOffset); $tempHtml = substr($tempHtml, $tagOffset);
} }
// Extract the attribute data from the html tag // Extract the attribute data from the html tag
preg_match_all('/([0-9A-Za-z]+(?:="[0-9A-Za-z\:\-\s\,\;\#]*")?)+/', $matches[2][0], $explodedAttributes); preg_match_all('/([0-9A-Za-z]+(?:="[0-9A-Za-z\:\-\s\,\;\#]*")?)+/', $matches[2][0], $explodedAttributes);
$explodedAttributes = array_filter($explodedAttributes[0]); $explodedAttributes = array_filter($explodedAttributes[0]);
$attributes = array(); $attributes = array();
// Store each attribute with its name in the $attributes array // Store each attribute with its name in the $attributes array
$explodedAttributesCount = count($explodedAttributes); $explodedAttributesCount = count($explodedAttributes);
for ($i=0; $i<$explodedAttributesCount; $i++) { for ($i=0; $i<$explodedAttributesCount; $i++) {
$attribute = trim($explodedAttributes[$i]); $attribute = trim($explodedAttributes[$i]);
// Check if the attribute has a value (like style="") or has no value (like required) // Check if the attribute has a value (like style="") or has no value (like required)
if (strpos($attribute, '=') !== false) { if (strpos($attribute, '=') !== false) {
$splitAttribute = explode('=', $attribute); $splitAttribute = explode('=', $attribute);
$attrName = trim($splitAttribute[0]); $attrName = trim($splitAttribute[0]);
$attrValue = trim(str_replace('"', '', $splitAttribute[1])); $attrValue = trim(str_replace('"', '', $splitAttribute[1]));
// check if the current attribute is a style attribute // check if the current attribute is a style attribute
if (strtolower($attrName) == 'style') { if (strtolower($attrName) == 'style') {
$attributes[$attrName] = array(); $attributes[$attrName] = array();
if (strpos($attrValue, ';') !== false) { if (strpos($attrValue, ';') !== false) {
// Split the style properties and store them in an array // Split the style properties and store them in an array
$explodedStyles = explode(';', $attrValue); $explodedStyles = explode(';', $attrValue);
$explodedStylesCount = count($explodedStyles); $explodedStylesCount = count($explodedStyles);
for ($n=0; $n<$explodedStylesCount; $n++) { for ($n=0; $n<$explodedStylesCount; $n++) {
$splitStyle = explode(':', $explodedStyles[$n]); $splitStyle = explode(':', $explodedStyles[$n]);
$attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]); $attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]);
} }
} else { } else {
$splitStyle = explode(':', $attrValue); $splitStyle = explode(':', $attrValue);
$attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]); $attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]);
} }
} else { } else {
// Store the value directly in the $attributes array if this is not the style attribute // Store the value directly in the $attributes array if this is not the style attribute
$attributes[$attrName] = $attrValue; $attributes[$attrName] = $attrValue;
} }
} else { } else {
$attributes[trim($attribute)] = true; $attributes[trim($attribute)] = true;
} }
} }
// Push the html tag data to the result array // Push the html tag data to the result array
array_push($tags, array( array_push($tags, array(
'name' => $matches[1][0], 'name' => $matches[1][0],
'attributes' => $attributes, 'attributes' => $attributes,
'innerText' => strip_tags($matches[3][0]), 'innerText' => strip_tags($matches[3][0]),
'children' => $this->_hasHtmlTag($matches[3][0]) ? $this->_getDataFromHtml($matches[3][0]) : null 'children' => $this->_hasHtmlTag($matches[3][0]) ? $this->_getDataFromHtml($matches[3][0]) : null
)); ));
// Remove the processed html tag from the html string // Remove the processed html tag from the html string
$tempHtml = substr($tempHtml, strlen($matches[0][0])); $tempHtml = substr($tempHtml, strlen($matches[0][0]));
} else { } else {
array_push($tags, array( array_push($tags, array(
'text' => $tempHtml 'text' => $tempHtml
)); ));
$tempHtml = ''; $tempHtml = '';
} }
} }
return $tags; return $tags;
} }
/** /**
@ -404,16 +403,15 @@ class Odf
// We convert html tags // We convert html tags
$ishtml=dol_textishtml($value); $ishtml=dol_textishtml($value);
if ($ishtml) if ($ishtml) {
{ // If string is "MYPODUCT - Desc <strong>bold</strong> with &eacute; accent<br />\n<br />\nUn texto en espa&ntilde;ol ?"
// If string is "MYPODUCT - Desc <strong>bold</strong> with &eacute; accent<br />\n<br />\nUn texto en espa&ntilde;ol ?" // Result after clean must be "MYPODUCT - Desc bold with é accent\n\nUn texto en espa&ntilde;ol ?"
// Result after clean must be "MYPODUCT - Desc bold with é accent\n\nUn texto en espa&ntilde;ol ?"
// We want to ignore \n and we want all <br> to be \n // 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('/(\r\n|\r|\n)/i', '', $value);
$value=preg_replace('/<br>/i',"\n",$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('/<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 text:style-name=__quot__bold__quot____gt__',$value);
//$value=preg_replace('/<\/strong>/','__lt__/text:p__gt__',$value); //$value=preg_replace('/<\/strong>/','__lt__/text:p__gt__',$value);
@ -448,15 +446,14 @@ class Odf
*/ */
public function phpEval() public function phpEval()
{ {
preg_match_all('/[\{\<]\?(php)?\s+(?P<content>.+)\?[\}\>]/iU',$this->contentXml, $matches); // detecting all {?php code ?} or <?php code ? > preg_match_all('/[\{\<]\?(php)?\s+(?P<content>.+)\?[\}\>]/iU', $this->contentXml, $matches); // detecting all {?php code ?} or <?php code ? >
$nbfound=count($matches['content']); $nbfound=count($matches['content']);
for ($i=0; $i < $nbfound; $i++) for ($i=0; $i < $nbfound; $i++) {
{
try { 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 $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]; $code = $matches['content'][$i];
ob_start(); ob_start();
eval ($code); eval($code);
$ob_output = ob_get_contents(); // send the content of the buffer into $ob_output $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); $this->contentXml = str_replace($matches[0][$i], $ob_output, $this->contentXml);
ob_end_clean(); ob_end_clean();
@ -503,12 +500,12 @@ IMG;
*/ */
private function _moveRowSegments() private function _moveRowSegments()
{ {
// Replace BEGIN<text:s/>xxx into BEGIN xxx // Replace BEGIN<text:s/>xxx into BEGIN xxx
$this->contentXml = preg_replace('/\[!--\sBEGIN<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- BEGIN \\1 --]', $this->contentXml); $this->contentXml = preg_replace('/\[!--\sBEGIN<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- BEGIN \\1 --]', $this->contentXml);
// Replace END<text:s/>xxx into END xxx // Replace END<text:s/>xxx into END xxx
$this->contentXml = preg_replace('/\[!--\sEND<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- END \\1 --]', $this->contentXml); $this->contentXml = preg_replace('/\[!--\sEND<text:s[^>]>(row.[\S]*)\s--\]/sm', '[!-- END \\1 --]', $this->contentXml);
// Search all possible rows in the document // Search all possible rows in the document
$reg1 = "#<table:table-row[^>]*>(.*)</table:table-row>#smU"; $reg1 = "#<table:table-row[^>]*>(.*)</table:table-row>#smU";
preg_match_all($reg1, $this->contentXml, $matches); preg_match_all($reg1, $this->contentXml, $matches);
for ($i = 0, $size = count($matches[0]); $i < $size; $i++) { for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
@ -536,31 +533,27 @@ IMG;
* @param string $type 'content', 'styles' or 'meta' * @param string $type 'content', 'styles' or 'meta'
* @return void * @return void
*/ */
private function _parse($type='content') private function _parse($type = 'content')
{ {
// Search all tags fou into condition to complete $this->vars, so we will proceed all tests even if not defined // 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'; $reg='@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU';
preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER); preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER);
//var_dump($this->vars);exit; //var_dump($this->vars);exit;
foreach($matches as $match) // For each match, if there is no entry into this->vars, we add it 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]])) {
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
{
$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; //var_dump($this->vars);exit;
// Conditionals substitution // 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 // 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) foreach ($this->vars as $key => $value) {
{
// If value is true (not 0 nor false nor null nor empty string) // If value is true (not 0 nor false nor null nor empty string)
if ($value) if ($value) {
{ //dol_syslog("Var ".$key." is defined, we remove the IF, ELSE and ENDIF ");
//dol_syslog("Var ".$key." is defined, we remove the IF, ELSE and ENDIF "); //$sav=$this->contentXml;
//$sav=$this->contentXml;
// Remove the IF tag // Remove the IF tag
$this->contentXml = str_replace('[!-- IF '.$key.' --]', '', $this->contentXml); $this->contentXml = str_replace('[!-- IF '.$key.' --]', '', $this->contentXml);
// Remove everything between the ELSE tag (if it exists) and the ENDIF tag // Remove everything between the ELSE tag (if it exists) and the ENDIF tag
@ -568,27 +561,26 @@ IMG;
$this->contentXml = preg_replace($reg, '', $this->contentXml); $this->contentXml = preg_replace($reg, '', $this->contentXml);
/*if ($sav != $this->contentXml) /*if ($sav != $this->contentXml)
{ {
dol_syslog("We found a IF and it was processed"); dol_syslog("We found a IF and it was processed");
//var_dump($sav);exit; //var_dump($sav);exit;
}*/ }*/
} }
// 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 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 else {
{ //dol_syslog("Var ".$key." is not defined, we remove the IF, ELSE and ENDIF ");
//dol_syslog("Var ".$key." is not defined, we remove the IF, ELSE and ENDIF "); //$sav=$this->contentXml;
//$sav=$this->contentXml;
// Find all conditional blocks for this variable: from IF to ELSE and to ENDIF // 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 $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); 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 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); if (!empty($match[3])) $this->contentXml = str_replace($match[0], $match[3], $this->contentXml);
} }
// Cleanup the other conditional blocks (all the others where there were no ELSE clause, we can just remove them altogether) // 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); $this->contentXml = preg_replace($reg, '', $this->contentXml);
/*if ($sav != $this->contentXml) /*if ($sav != $this->contentXml)
{ {
dol_syslog("We found a IF and it was processed"); dol_syslog("We found a IF and it was processed");
//var_dump($sav);exit; //var_dump($sav);exit;
}*/ }*/
} }
} }
@ -597,7 +589,6 @@ IMG;
if ($type == 'content') $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml); 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 == '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); if ($type == 'meta') $this->metaXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->metaXml);
} }
/** /**
@ -737,21 +728,19 @@ IMG;
*/ */
public function setMetaData() public function setMetaData()
{ {
if (empty($this->creator)) $this->creator=''; 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: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: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: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); $this->metaXml = preg_replace('/<dc:subject>.*<\/dc:subject>/', '<dc:subject>'.htmlspecialchars($this->subject).'</dc:subject>', $this->metaXml);
if (count($this->userdefined)) if (count($this->userdefined)) {
{ foreach ($this->userdefined as $key => $val) {
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 = preg_replace('<meta:user-defined meta:name="'.$key.'"/>', '', $this->metaXml); $this->metaXml = str_replace('</office:meta>', '<meta:user-defined meta:name="'.$key.'">'.htmlspecialchars($val).'</meta:user-defined></office:meta>', $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);
}
} }
} }
@ -785,8 +774,7 @@ IMG;
throw new OdfException("headers already sent ($filename at $linenum)"); throw new OdfException("headers already sent ($filename at $linenum)");
} }
if( $name == "" ) if ( $name == "" ) {
{
$name = md5(uniqid()) . ".odt"; $name = md5(uniqid()) . ".odt";
} }
@ -804,11 +792,11 @@ IMG;
* @throws OdfException * @throws OdfException
* @return void * @return void
*/ */
public function exportAsAttachedPDF($name="") public function exportAsAttachedPDF($name = "")
{ {
global $conf; global $conf;
if( $name == "" ) $name = "temp".md5(uniqid()); if ( $name == "" ) $name = "temp".md5(uniqid());
dol_syslog(get_class($this).'::exportAsAttachedPDF $name='.$name, LOG_DEBUG); dol_syslog(get_class($this).'::exportAsAttachedPDF $name='.$name, LOG_DEBUG);
$this->saveToDisk($name); $this->saveToDisk($name);
@ -818,8 +806,7 @@ IMG;
// Export to PDF using LibreOffice // Export to PDF using LibreOffice
if ($conf->global->MAIN_ODT_AS_PDF == 'libreoffice') if ($conf->global->MAIN_ODT_AS_PDF == 'libreoffice') {
{
dol_mkdir($conf->user->dir_temp); // We must be sure the directory exists and is writable dol_mkdir($conf->user->dir_temp); // We must be sure the directory exists and is writable
// We delete and recreate a subdir because the soffice may have change pemrissions on it // We delete and recreate a subdir because the soffice may have change pemrissions on it
@ -831,9 +818,7 @@ IMG;
// using linux/mac 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 // Note PHP Config "fastcgi.impersonate=0" must set to 0 - Default is 1
$command ='soffice --headless -env:UserInstallation=file:\''.$conf->user->dir_temp.'/odtaspdf\' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name); $command ='soffice --headless -env:UserInstallation=file:\''.$conf->user->dir_temp.'/odtaspdf\' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name);
} } elseif (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF)) {
elseif (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF))
{
// If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87 // 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 . // 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 .
@ -860,19 +845,14 @@ IMG;
$command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name); $command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name);
//$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name); //$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name);
} } else {
else
{
// deprecated old method using odt2pdf.sh (native, jodconverter, ...) // deprecated old method using odt2pdf.sh (native, jodconverter, ...)
$tmpname=preg_replace('/\.odt/i', '', $name); $tmpname=preg_replace('/\.odt/i', '', $name);
if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) {
{
$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); $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);
} } else {
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);
{
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($tmpname).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); $command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($tmpname).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF);
} }
} }
@ -880,25 +860,26 @@ IMG;
//$dirname=dirname($name); //$dirname=dirname($name);
//$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname; //$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname;
dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command,LOG_DEBUG); dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command, LOG_DEBUG);
// TODO Use:
// $outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
// $result = $utils->executeCLI($command, $outputfile); and replace test on $execmethod.
// $retval will be $result['result']
// $errorstring will be $result['output']
$retval=0; $output_arr=array(); $retval=0; $output_arr=array();
if ($execmethod == 1) if ($execmethod == 1) {
{
exec($command, $output_arr, $retval); exec($command, $output_arr, $retval);
} }
if ($execmethod == 2) if ($execmethod == 2) {
{
$outputfile = DOL_DATA_ROOT.'/odt2pdf.log'; $outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
$ok=0; $ok=0;
$handle = fopen($outputfile, 'w'); $handle = fopen($outputfile, 'w');
if ($handle) if ($handle) {
{ dol_syslog(get_class($this)."Run command ".$command, LOG_DEBUG);
dol_syslog(get_class($this)."Run command ".$command,LOG_DEBUG);
fwrite($handle, $command."\n"); fwrite($handle, $command."\n");
$handlein = popen($command, 'r'); $handlein = popen($command, 'r');
while (!feof($handlein)) while (!feof($handlein)) {
{
$read = fgets($handlein); $read = fgets($handlein);
fwrite($handle, $read); fwrite($handle, $read);
$output_arr[]=$read; $output_arr[]=$read;
@ -909,8 +890,7 @@ IMG;
if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK)); 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); dol_syslog(get_class($this).'::exportAsAttachedPDF $ret_val='.$retval, LOG_DEBUG);
$filename=''; $linenum=0; $filename=''; $linenum=0;
@ -927,8 +907,7 @@ IMG;
} }
} }
if (!empty($conf->global->MAIN_ODT_AS_PDF_DEL_SOURCE)) if (!empty($conf->global->MAIN_ODT_AS_PDF_DEL_SOURCE)) {
{
unlink($name); unlink($name);
} }
} else { } else {
@ -937,11 +916,10 @@ IMG;
if ($retval == 126) { if ($retval == 126) {
throw new OdfException('Permission execute convert script : ' . $command); throw new OdfException('Permission execute convert script : ' . $command);
} } else {
else { $errorstring='';
$errorstring=''; foreach ($output_arr as $line) {
foreach($output_arr as $line) { $errorstring.= $line."<br>";
$errorstring.= $line."<br>";
} }
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); 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);
} }

View File

@ -142,7 +142,7 @@ if ($socid > 0) {
// Total Margin // Total Margin
print '<tr><td class="titlefield">'.$langs->trans("TotalMargin").'</td><td colspan="3">'; print '<tr><td class="titlefield">'.$langs->trans("TotalMargin").'</td><td colspan="3">';
print '<span id="totalMargin"></span>'; // set by jquery (see below) print '<span id="totalMargin" class="amount"></span>'; // set by jquery (see below)
print '</td></tr>'; print '</td></tr>';
// Margin Rate // Margin Rate
@ -242,9 +242,9 @@ if ($socid > 0) {
print "</td>\n"; print "</td>\n";
print "<td class=\"center\">"; print "<td class=\"center\">";
print dol_print_date($db->jdate($objp->datef), 'day')."</td>"; print dol_print_date($db->jdate($objp->datef), 'day')."</td>";
print "<td class=\"right\">".price(price2num($objp->selling_price, 'MT'))."</td>\n"; print "<td class=\"right amount\">".price(price2num($objp->selling_price, 'MT'))."</td>\n";
print "<td class=\"right\">".price(price2num(($objp->type == 2 ? -1 : 1) * $objp->buying_price, 'MT'))."</td>\n"; print "<td class=\"right amount\">".price(price2num(($objp->type == 2 ? -1 : 1) * $objp->buying_price, 'MT'))."</td>\n";
print "<td class=\"right\">".$sign.price(price2num($objp->marge, 'MT'))."</td>\n"; print "<td class=\"right amount\">".$sign.price(price2num($objp->marge, 'MT'))."</td>\n";
if (!empty($conf->global->DISPLAY_MARGIN_RATES)) { if (!empty($conf->global->DISPLAY_MARGIN_RATES)) {
print "<td class=\"right\">".(($marginRate === '') ? 'n/a' : $sign.price(price2num($marginRate, 'MT'))."%")."</td>\n"; print "<td class=\"right\">".(($marginRate === '') ? 'n/a' : $sign.price(price2num($marginRate, 'MT'))."%")."</td>\n";
} }

View File

@ -2640,7 +2640,7 @@ table.login_table_securitycode tr td {
} }
div.backgroundsemitransparent { div.backgroundsemitransparent {
background:rgba(255,255,255,0.68); background:rgba(255, 255, 255, 0.7);
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
} }
@ -3922,6 +3922,11 @@ table.noborder.paymenttable {
box-shadow: 1px 1px 7px #CCC !important; box-shadow: 1px 1px 7px #CCC !important;
} }
.boxshadow {
-webkit-box-shadow: 0px 0px 5px #888;
box-shadow: 0px 0px 5px #888;
}
div.tabBar .noborder { div.tabBar .noborder {
-webkit-box-shadow: 0px 0px 0px #DDD !important; -webkit-box-shadow: 0px 0px 0px #DDD !important;
box-shadow: 0px 0px 0px #DDD !important; box-shadow: 0px 0px 0px #DDD !important;

View File

@ -1862,7 +1862,7 @@ div.login_block {
div.backgroundsemitransparent { div.backgroundsemitransparent {
background:rgba(255,255,255,0.6); background:rgba(255, 255, 255, 0.7);
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
} }
@ -3943,6 +3943,11 @@ tr.liste_sub_total, tr.liste_sub_total td {
box-shadow: 2px 2px 5px #CCC !important; box-shadow: 2px 2px 5px #CCC !important;
} }
.boxshadow {
-webkit-box-shadow: 0px 0px 5px #888;
box-shadow: 0px 0px 5px #888;
}
div.tabBar .noborder { div.tabBar .noborder {
-webkit-box-shadow: 0px 0px 0px #f4f4f4 !important; -webkit-box-shadow: 0px 0px 0px #f4f4f4 !important;
box-shadow: 0px 0px 0px #f4f4f4 !important; box-shadow: 0px 0px 0px #f4f4f4 !important;

View File

@ -188,7 +188,7 @@ print '<table class="noborder centpercent">';
print "<tr class=\"liste_titre\">"; print "<tr class=\"liste_titre\">";
print "<td>".$langs->trans("Parameter")."</td>"; print "<td>".$langs->trans("Parameter")."</td>";
print "<td>".$langs->trans("Name")."</td>"; print "<td>".$langs->trans("Name")."</td>";
print "<td>".$langs->trans("ExtSiteUrlAgenda").'<div class="hideonsmartphone">'." (".$langs->trans("Example").': http://yoursite/agenda/agenda.ics)</div></td>'; print "<td>".$langs->trans("ExtSiteUrlAgenda").'<div class="hideonsmartphone opacitymedium">'." (".$langs->trans("Example").': https://externalcalendar/agenda/agenda.ics)</div></td>';
print "<td>".$form->textwithpicto($langs->trans("FixTZ"), $langs->trans("FillFixTZOnlyIfRequired"), 1).'</td>'; print "<td>".$form->textwithpicto($langs->trans("FixTZ"), $langs->trans("FillFixTZOnlyIfRequired"), 1).'</td>';
print '<td class="right">'.$langs->trans("Color").'</td>'; print '<td class="right">'.$langs->trans("Color").'</td>';
print "</tr>"; print "</tr>";

View File

@ -1421,10 +1421,12 @@ if ($action == 'create' || $action == 'adduserldap') {
if ($object->socid > 0) { if ($object->socid > 0) {
$type = $langs->trans("External"); $type = $langs->trans("External");
} }
print '<span class="badgeneutral">';
print $type; print $type;
if ($object->ldap_sid) { if ($object->ldap_sid) {
print ' ('.$langs->trans("DomainUser").')'; print ' ('.$langs->trans("DomainUser").')';
} }
print '</span>';
print '</td></tr>'."\n"; print '</td></tr>'."\n";
// Ldap sid // Ldap sid
@ -1534,7 +1536,7 @@ if ($action == 'create' || $action == 'adduserldap') {
// Salary // Salary
print '<tr><td>'.$langs->trans("Salary").'</td>'; print '<tr><td>'.$langs->trans("Salary").'</td>';
print '<td>'; print '<td>';
print ($object->salary != '' ? img_picto('', 'salary', 'class="pictofixedwidth paddingright"').price($object->salary, '', $langs, 1, -1, -1, $conf->currency) : ''); print ($object->salary != '' ? img_picto('', 'salary', 'class="pictofixedwidth paddingright"').'<span class="amount">'.price($object->salary, '', $langs, 1, -1, -1, $conf->currency) : '').'</span>';
print '</td>'; print '</td>';
print "</tr>\n"; print "</tr>\n";
} }

View File

@ -128,7 +128,7 @@ if (empty($reshook)) {
} }
if ($result <= 0 && $edituser->error == 'USERNOTFOUND') { if ($result <= 0 && $edituser->error == 'USERNOTFOUND') {
$message = '<div class="warning paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent').'">'; $message = '<div class="warning paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'">';
if (!$isanemail) { if (!$isanemail) {
$message .= $langs->trans("IfLoginExistPasswordRequestSent"); $message .= $langs->trans("IfLoginExistPasswordRequestSent");
} else { } else {
@ -147,7 +147,7 @@ if (empty($reshook)) {
} else { } else {
// Success // Success
if ($edituser->send_password($user, $newpassword, 1) > 0) { if ($edituser->send_password($user, $newpassword, 1) > 0) {
$message = '<div class="warning paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent').'">'; $message = '<div class="warning paddingtopbottom'.(empty($conf->global->MAIN_LOGIN_BACKGROUND) ? '' : ' backgroundsemitransparent boxshadow').'">';
if (!$isanemail) { if (!$isanemail) {
$message .= $langs->trans("IfLoginExistPasswordRequestSent"); $message .= $langs->trans("IfLoginExistPasswordRequestSent");
} else { } else {

View File

@ -798,8 +798,8 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$result=dol_sanitizeFileName('bad file | evilaction'); $result=dol_sanitizeFileName('bad file | evilaction');
$this->assertEquals('bad file _ evilaction', $result); $this->assertEquals('bad file _ evilaction', $result);
$result=dol_sanitizeFileName('bad file --evilparam'); $result=dol_sanitizeFileName('bad file -evilparam --evilparam ---evilparam ----evilparam');
$this->assertEquals('bad file _evilparam', $result); $this->assertEquals('bad file _evilparam _evilparam _evilparam _evilparam', $result);
} }
/** /**