diff --git a/gulliver/system/class.g.php b/gulliver/system/class.g.php index 60207b1be..0b39f7d33 100644 --- a/gulliver/system/class.g.php +++ b/gulliver/system/class.g.php @@ -1636,13 +1636,16 @@ class G /** * Escapes special characters in a string for use in a SQL statement - * @param string $sqlString The string to be escaped - * @param string $DBEngine Target DBMS - */ - public function sqlEscape($sqlString, $DBEngine = DB_ADAPTER) + * @param string $sqlString The string to be escaped + * @param string $dbEngine Target DBMS + * + * @return string + */ + public static function sqlEscape($sqlString, $dbEngine = DB_ADAPTER) { - $DBEngine = DB_ADAPTER; - switch ($DBEngine) { + // @todo: Research why always this value is set with the same constant? + $dbEngine = DB_ADAPTER; + switch ($dbEngine) { case 'mysql': $con = Propel::getConnection('workflow'); return mysqli_real_escape_string($con->getResource(), stripslashes($sqlString)); @@ -1689,9 +1692,15 @@ class G * @# Non-quoted parameter * @! Evaluate string : Replace the parameters in value and then in the sql string * @fn() Evaluate string with the function "fn" - * @author David Callizaya + * + * @param string $sqlString + * @param array $result + * @param string $dbEngine + * @param bool $applyHtmlEntities + * + * @return string */ - public static function replaceDataField($sqlString, $result, $DBEngine = 'mysql') + public static function replaceDataField($sqlString, $result, $dbEngine = 'mysql', $applyHtmlEntities = false) { if (!is_array($result)) { $result = array(); @@ -1710,7 +1719,12 @@ class G $u = $match[0][$r][1] + strlen($match[0][$r][0]); //Mysql quotes scape if (($match[1][$r][0] == '@') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= "\"" . G::sqlEscape($result[$match[2][$r][0]], $DBEngine) . "\""; + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= "\"" . G::sqlEscape($text, $dbEngine) . "\""; continue; } //URL encode @@ -1730,7 +1744,7 @@ class G } //Substring (Sub replaceDataField) if (($match[1][$r][0] == '!') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result, $dbEngine, $applyHtmlEntities); continue; } //Call function @@ -1748,18 +1762,33 @@ class G } //Non-quoted if (($match[1][$r][0] == '#') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= G::replaceDataField($text, $result); continue; } //Non-quoted = if (($match[1][$r][0] == '=') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= G::replaceDataField($text, $result); continue; } //Objects attributes if (($match[1][$r][0] == '&') && (isset($result[$match[2][$r][0]]))) { if (isset($result[$match[2][$r][0]]->{$match[6][$r][0]})) { - $__textoEval .= $result[$match[2][$r][0]]->{$match[6][$r][0]}; + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]]->{$match[6][$r][0]})) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]->{$match[6][$r][0]}), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]->{$match[6][$r][0]}; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= $text; } continue; } @@ -1771,27 +1800,36 @@ class G } /** - * Replace Grid Values - * The tag @>GRID-NAME to open the grid and @GRID-NAME to open the grid and @sendMessage() + * @see \WsBase->sendMessage() + * @see \OutputDocument->generate() + * @see \ProcessMaker\BusinessModel\Cases\OutputDocument->generate() + */ + public static function replaceDataGridField($content, $fields, $nl2brRecursive = true, $applyHtmlEntities = false) { $nrt = array("\n", "\r", "\t"); $nrthtml = array("(n /)", "(r /)", "(t /)"); - $sContent = G::unhtmlentities($sContent); - $strContentAux = str_replace($nrt, $nrthtml, $sContent); + $content = G::unhtmlentities($content); + $strContentAux = str_replace($nrt, $nrthtml, $content); - $iOcurrences = preg_match_all('/\@(?:([\>])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+)?/', $strContentAux, $arrayMatch1, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE); + $occurrences = preg_match_all('/\@(?:([\>])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+)?/', + $strContentAux, $arrayMatch1, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE); - if ($iOcurrences) { + if ($occurrences) { $arrayGrid = array(); - for ($i = 0; $i <= $iOcurrences - 1; $i++) { + for ($i = 0; $i <= $occurrences - 1; $i++) { $arrayGrid[] = $arrayMatch1[2][$i][0]; } @@ -1817,16 +1855,16 @@ class G while (preg_match($ereg, $strContentAux1, $arrayMatch2)) { $strData = null; - if (isset($aFields[$grdName]) && is_array($aFields[$grdName])) { - foreach ($aFields[$grdName] as $aRow) { + if (isset($fields[$grdName]) && is_array($fields[$grdName])) { + foreach ($fields[$grdName] as $aRow) { if ($nl2brRecursive) { - foreach ($aRow as $sKey => $vValue) { - if (!is_array($vValue)) { - $aRow[$sKey] = str_replace($nrt, $nrthtml, nl2br($aRow[$sKey])); + foreach ($aRow as $key => $item) { + if (!is_array($item)) { + $aRow[$key] = str_replace($nrt, $nrthtml, nl2br($aRow[$key])); } } } - $strData = $strData . G::replaceDataField($arrayMatch2[2], $aRow); + $strData = $strData . G::replaceDataField($arrayMatch2[2], $aRow, 'mysql', $applyHtmlEntities); } } @@ -1841,19 +1879,19 @@ class G $strContentAux = str_replace($nrthtml, $nrt, $strContentAux); - $sContent = $strContentAux; + $content = $strContentAux; if ($nl2brRecursive) { - foreach ($aFields as $sKey => $vValue) { - if (!is_array($vValue) && !is_object($vValue)) { - $aFields[$sKey] = nl2br($aFields[$sKey]); + foreach ($fields as $key => $item) { + if (!is_array($item) && !is_object($item)) { + $fields[$key] = nl2br($fields[$key]); } } } - $sContent = G::replaceDataField($sContent, $aFields); + $content = G::replaceDataField($content, $fields, 'mysql', $applyHtmlEntities); - return $sContent; + return $content; } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index ed5442c3f..af24f74b8 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -22,6 +22,7 @@ define('PATH_DATA', 'shared/rbac/'); define('PATH_SEP', '/'); define('PATH_METHODS', 'workflow/engine/methods/'); define('SYS_LANG', 'en'); +define('DB_ADAPTER', 'mysql'); // Setup basic app services $app = require __DIR__ . '/../bootstrap/app.php'; diff --git a/tests/unit/gulliver/system/ReplaceDataFieldTest.php b/tests/unit/gulliver/system/ReplaceDataFieldTest.php new file mode 100644 index 000000000..e4445024c --- /dev/null +++ b/tests/unit/gulliver/system/ReplaceDataFieldTest.php @@ -0,0 +1,252 @@ +value'; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // If a value to replace is a not valid HTML and have HTML reserved characters, entities should be applied + + // Initializing variables to test the assertions, entities should be applied in variable with @@ + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => 'Java < PHP & Python', + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @# + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => 'Java < PHP & Python', + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @= + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => 'Java < PHP & Python', + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @& + $var4 = new stdClass(); + $var4->value = 'Java < PHP & Python'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + } + + /** + * This checks that strings with HTML reserved characters are NOT replaced with entities + * @test + */ + public function it_should_no_replace_entities() + { + // Initializing Faker instance + $faker = Faker\Factory::create(); + + // Initializing variables to use that will not change + $stringWithVariablesToReplace = 'Hello @@var1 the @#var2 is @=var3 not @&var4->value'; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = false; // The values should not be replaced with entities + + // Initializing variables to test the assertions, entities should be applied in variable with @@ + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => 'Java < PHP & Python', + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @# + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => 'Java < PHP & Python', + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @= + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => 'Java < PHP & Python', + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @& + $var4 = new stdClass(); + $var4->value = 'Java < PHP & Python'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + } + + /** + * This checks that strings with HTML reserved characters are NOT replaced with entities if is a valid HTML, because + * PS team sometimes build a HTML string to insert in templates (output documents or emails), Ex.- A table to list + * users or results from a query + * @test + */ + public function it_should_no_replace_entities_if_exists_valid_html() + { + // Initializing Faker instance + $faker = Faker\Factory::create(); + + // Initializing variables to use + $stringWithVariablesToReplace = 'bla @#var1 bla @=listHtml bla @@var2 bla'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'listHtml' => ' + + + + + + + + + + + + + + + + +
t1t2t3t4t5t6
c1c2c3c4c5c6
', + 'var2' => $faker->words(1, true) + ]; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // Is true because the string will b used in a output document or a email template + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('//', $stringToCheck); + $this->assertRegExp('//', $stringToCheck); + $this->assertRegExp('/
/', $stringToCheck); + $this->assertRegExp('//', $stringToCheck); + } + + /** + * This checks that strings with tag
should not be replaced, because is a valid tag + * @test + */ + public function it_should_no_replace_tag_br() + { + // Initializing variables to use + $stringWithTagBr = nl2br("prospection auprès d'entreprises de CA < 10 M euros +test +a +&a +\"a +'a +¢a +£a +¥a +€a +©a +®a +test"); + $valuesToReplace = []; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // Is true because the string will b used in a output document or a email template + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithTagBr, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp("/
/", $stringToCheck); + } +} diff --git a/workflow/engine/classes/Cases.php b/workflow/engine/classes/Cases.php index 85f17b524..0718aa6bb 100644 --- a/workflow/engine/classes/Cases.php +++ b/workflow/engine/classes/Cases.php @@ -5612,30 +5612,30 @@ class Cases /** * This function send an email for each task in $arrayTask if $to is definded * - * @param $dataLastEmail - * @param $arrayData - * @param $arrayTask + * @param array $dataLastEmail + * @param array $arrayData + * @param array $arrayTask * @return void * * @see \Cases->sendNotifications() */ public function sendMessage($dataLastEmail, $arrayData, $arrayTask) { - foreach ($arrayTask as $aTask) { + foreach ($arrayTask as $theTask) { //Check and fix if Task Id is complex - if (strpos($aTask['TAS_UID'], "/") !== false) { - $aux = explode("/", $aTask['TAS_UID']); + if (strpos($theTask['TAS_UID'], "/") !== false) { + $aux = explode("/", $theTask['TAS_UID']); if (isset($aux[1])) { - $aTask['TAS_UID'] = $aux[1]; + $theTask['TAS_UID'] = $aux[1]; } } //if the next is EOP dont send notification and continue with the next - if ($aTask['TAS_UID'] === '-1') { + if ($theTask['TAS_UID'] === '-1') { continue; } - if (isset($aTask['DEL_INDEX'])) { + if (isset($theTask['DEL_INDEX'])) { $arrayData2 = $arrayData; - $appDelegation = AppDelegationPeer::retrieveByPK($dataLastEmail['applicationUid'], $aTask['DEL_INDEX']); + $appDelegation = AppDelegationPeer::retrieveByPK($dataLastEmail['applicationUid'], $theTask['DEL_INDEX']); if (!is_null($appDelegation)) { $oTaskUpd = new Task(); $aTaskUpdate = $oTaskUpd->load($appDelegation->getTasUid()); @@ -5646,25 +5646,25 @@ class Cases $arrayData2 = $arrayData; } - if (isset($aTask['USR_UID']) && !empty($aTask['USR_UID'])) { + if (isset($theTask['USR_UID']) && !empty($theTask['USR_UID'])) { $user = new \ProcessMaker\BusinessModel\User(); - $arrayUserData = $user->getUser($aTask['USR_UID'], true); + $arrayUserData = $user->getUser($theTask['USR_UID'], true); $arrayData2 = \ProcessMaker\Util\DateTime::convertUtcToTimeZone($arrayData2, (trim($arrayUserData['USR_TIME_ZONE']) != '') ? trim($arrayUserData['USR_TIME_ZONE']) : \ProcessMaker\Util\System::getTimeZone()); } else { $arrayData2 = \ProcessMaker\Util\DateTime::convertUtcToTimeZone($arrayData2); } - $body2 = G::replaceDataGridField($dataLastEmail['body'], $arrayData2, false); + $body2 = G::replaceDataGridField($dataLastEmail['body'], $arrayData2, false, true); $to = null; $cc = ''; - if ($aTask['TAS_UID'] != '-1') { - $respTo = $this->getTo($aTask['TAS_UID'], $aTask['USR_UID'], $arrayData); + if ($theTask['TAS_UID'] != '-1') { + $respTo = $this->getTo($theTask['TAS_UID'], $theTask['USR_UID'], $arrayData); $to = $respTo['to']; $cc = $respTo['cc']; } - if ($aTask ["TAS_ASSIGN_TYPE"] === "SELF_SERVICE") { + if ($theTask["TAS_ASSIGN_TYPE"] === "SELF_SERVICE") { if ($dataLastEmail['swtplDefault'] == 1) { G::verifyPath($dataLastEmail['pathEmail'], true); // Create if it does not exist $fileTemplate = $dataLastEmail['pathEmail'] . G::LoadTranslation('ID_UNASSIGNED_MESSAGE'); diff --git a/workflow/engine/classes/WsBase.php b/workflow/engine/classes/WsBase.php index afedb88ec..ebea4bbe4 100644 --- a/workflow/engine/classes/WsBase.php +++ b/workflow/engine/classes/WsBase.php @@ -990,7 +990,7 @@ class WsBase $subject, G::buildFrom($setup, $from), $to, - G::replaceDataGridField(file_get_contents($fileTemplate), $fieldsCase, false), + G::replaceDataGridField(file_get_contents($fileTemplate), $fieldsCase, false, true), $cc, $bcc, '', diff --git a/workflow/engine/classes/model/OutputDocument.php b/workflow/engine/classes/model/OutputDocument.php index 37da4fbf9..3d8f393e4 100644 --- a/workflow/engine/classes/model/OutputDocument.php +++ b/workflow/engine/classes/model/OutputDocument.php @@ -508,20 +508,29 @@ class OutputDocument extends BaseOutputDocument } } - /* + /** * Generate the output document - * @param string $sUID - * @param array $aFields - * @param string $sPath - * @return variant + * + * @param string $outDocUid + * @param array $caseFields + * @param string $path + * @param string $filename + * @param string $content + * @param bool $landscape + * @param string $typeDocsToGen + * @param array $properties + * + * @return mixed + * + * @see workflow/engine/methods/cases/cases_Step.php + * @see workflow/engine/classes/class.pmFunctions.php:PMFGenerateOutputDocument() */ - - public function generate($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape = false, $sTypeDocToGener = 'BOTH', $aProperties = array()) + public function generate($outDocUid, $caseFields, $path, $filename, $content, $landscape = false, $typeDocsToGen = 'BOTH', $properties = []) { - if (($sUID != '') && is_array($aFields) && ($sPath != '')) { - $sContent = G::replaceDataGridField($sContent, $aFields); + if (($outDocUid != '') && is_array($caseFields) && ($path != '')) { + $content = G::replaceDataGridField($content, $caseFields, true, true); - if (strpos($sContent, ''; - $oFile = fopen($sPath . $sFilename . '_smarty.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); - $template->templateFile = $sPath . $sFilename . '_smarty.html'; + $fp = fopen($path . $filename . '_smarty.html', 'wb'); + fwrite($fp, $content); + fclose($fp); + $template->templateFile = $path . $filename . '_smarty.html'; //assign the variables and use the template $template - $template->assign($aFields); - $sContent = $template->fetch($template->templateFile); + $template->assign($caseFields); + $content = $template->fetch($template->templateFile); unlink($template->templateFile); } - G::verifyPath($sPath, true); + G::verifyPath($path, true); //Start - Create .doc - $oFile = fopen($sPath . $sFilename . '.doc', 'wb'); + $fp = fopen($path . $filename . '.doc', 'wb'); $size = []; $size["Letter"] = "216mm 279mm"; @@ -566,6 +575,7 @@ class OutputDocument extends BaseOutputDocument $size["Screenshot800"] = "800mm 600mm"; $size["Screenshot1024"] = "1024mm 768mm"; + $sizeLandscape = []; $sizeLandscape["Letter"] = "279mm 216mm"; $sizeLandscape["Legal"] = "357mm 216mm"; $sizeLandscape["Executive"] = "267mm 184mm"; @@ -587,41 +597,41 @@ class OutputDocument extends BaseOutputDocument $sizeLandscape["Screenshot800"] = "600mm 800mm"; $sizeLandscape["Screenshot1024"] = "768mm 1024mm"; - if (!isset($aProperties['media'])) { - $aProperties['media'] = 'Letter'; + if (!isset($properties['media'])) { + $properties['media'] = 'Letter'; } - if ($sLandscape) { - $media = $sizeLandscape[$aProperties['media']]; + if ($landscape) { + $media = $sizeLandscape[$properties['media']]; } else { - $media = $size[$aProperties['media']]; + $media = $size[$properties['media']]; } $marginLeft = '15'; - if (isset($aProperties['margins']['left'])) { - $marginLeft = $aProperties['margins']['left']; + if (isset($properties['margins']['left'])) { + $marginLeft = $properties['margins']['left']; } $marginRight = '15'; - if (isset($aProperties['margins']['right'])) { - $marginRight = $aProperties['margins']['right']; + if (isset($properties['margins']['right'])) { + $marginRight = $properties['margins']['right']; } $marginTop = '15'; - if (isset($aProperties['margins']['top'])) { - $marginTop = $aProperties['margins']['top']; + if (isset($properties['margins']['top'])) { + $marginTop = $properties['margins']['top']; } $marginBottom = '15'; - if (isset($aProperties['margins']['bottom'])) { - $marginBottom = $aProperties['margins']['bottom']; + if (isset($properties['margins']['bottom'])) { + $marginBottom = $properties['margins']['bottom']; } - fwrite($oFile, ' @@ -667,31 +677,31 @@ class OutputDocument extends BaseOutputDocument
'); - fwrite($oFile, $sContent); - fwrite($oFile, "\n
\n\n"); - fclose($oFile); + fwrite($fp, $content); + fwrite($fp, "\n\n\n"); + fclose($fp); /* End - Create .doc */ - if ($sTypeDocToGener == 'BOTH' || $sTypeDocToGener == 'PDF') { - $oFile = fopen($sPath . $sFilename . '.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); + if ($typeDocsToGen == 'BOTH' || $typeDocsToGen == 'PDF') { + $fp = fopen($path . $filename . '.html', 'wb'); + fwrite($fp, $content); + fclose($fp); /* Start - Create .pdf */ - if (isset($aProperties['report_generator'])) { - switch ($aProperties['report_generator']) { + if (isset($properties['report_generator'])) { + switch ($properties['report_generator']) { case 'TCPDF': - $this->generateTcpdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateTcpdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); break; case 'HTML2PDF': default: - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); break; } } else { - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } } - //end if $sTypeDocToGener + //end if $typeDocsToGen /* End - Create .pdf */ } else { return PEAR::raiseError( diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php index 01652bfd9..553dd35e5 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php @@ -1,6 +1,9 @@ addCasesOutputDocument() */ - public function generate($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape = false, $sTypeDocToGener = 'BOTH', $aProperties = array(), $sApplication) + public function generate($outDocUid, $caseFields, $path, $filename, $content, $landscape = false, $typeDocsToGen = 'BOTH', $properties = [], $application = '') { - if (($sUID != '') && is_array($aFields) && ($sPath != '')) { - $sContent = \G::replaceDataGridField($sContent, $aFields); - \G::verifyPath($sPath, true); + if (($outDocUid != '') && is_array($caseFields) && ($path != '')) { + $content = G::replaceDataGridField($content, $caseFields, true, true); + G::verifyPath($path, true); //Start - Create .doc - $oFile = fopen($sPath . $sFilename . '.doc', 'wb'); - $size = array(); + $fp = fopen($path . $filename . '.doc', 'wb'); + $size = []; $size["Letter"] = "216mm 279mm"; $size["Legal"] = "216mm 357mm"; $size["Executive"] = "184mm 267mm"; @@ -627,6 +640,7 @@ class OutputDocument $size["Screenshot640"] = "640mm 480mm"; $size["Screenshot800"] = "800mm 600mm"; $size["Screenshot1024"] = "1024mm 768mm"; + $sizeLandscape = []; $sizeLandscape["Letter"] = "279mm 216mm"; $sizeLandscape["Legal"] = "357mm 216mm"; $sizeLandscape["Executive"] = "267mm 184mm"; @@ -647,31 +661,31 @@ class OutputDocument $sizeLandscape["Screenshot640"] = "480mm 640mm"; $sizeLandscape["Screenshot800"] = "600mm 800mm"; $sizeLandscape["Screenshot1024"] = "768mm 1024mm"; - if (!isset($aProperties['media'])) { - $aProperties['media'] = 'Letter'; + if (!isset($properties['media'])) { + $properties['media'] = 'Letter'; } - if ($sLandscape) { - $media = $sizeLandscape[$aProperties['media']]; + if ($landscape) { + $media = $sizeLandscape[$properties['media']]; } else { - $media = $size[$aProperties['media']]; + $media = $size[$properties['media']]; } $marginLeft = '15'; - if (isset($aProperties['margins']['left'])) { - $marginLeft = $aProperties['margins']['left']; + if (isset($properties['margins']['left'])) { + $marginLeft = $properties['margins']['left']; } $marginRight = '15'; - if (isset($aProperties['margins']['right'])) { - $marginRight = $aProperties['margins']['right']; + if (isset($properties['margins']['right'])) { + $marginRight = $properties['margins']['right']; } $marginTop = '15'; - if (isset($aProperties['margins']['top'])) { - $marginTop = $aProperties['margins']['top']; + if (isset($properties['margins']['top'])) { + $marginTop = $properties['margins']['top']; } $marginBottom = '15'; - if (isset($aProperties['margins']['bottom'])) { - $marginBottom = $aProperties['margins']['bottom']; + if (isset($properties['margins']['bottom'])) { + $marginBottom = $properties['margins']['bottom']; } - fwrite($oFile, ' @@ -716,40 +730,40 @@ class OutputDocument
'); - fwrite($oFile, $sContent); - fwrite($oFile, "\n
\n\n"); - fclose($oFile); + fwrite($fp, $content); + fwrite($fp, "\n\n\n"); + fclose($fp); /* End - Create .doc */ - if ($sTypeDocToGener == 'BOTH' || $sTypeDocToGener == 'PDF') { - $oFile = fopen($sPath . $sFilename . '.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); + if ($typeDocsToGen == 'BOTH' || $typeDocsToGen == 'PDF') { + $fp = fopen($path . $filename . '.html', 'wb'); + fwrite($fp, $content); + fclose($fp); /* Start - Create .pdf */ - if (isset($aProperties['report_generator'])) { - switch ($aProperties['report_generator']) { + if (isset($properties['report_generator'])) { + switch ($properties['report_generator']) { case 'TCPDF': - $o = new \OutputDocument(); - if (strlen($sContent) == 0) { + $o = new ClassesOutputDocument(); + if (strlen($content) == 0) { libxml_use_internal_errors(true); - $o->generateTcpdf($sUID, $aFields, $sPath, $sFilename, ' ', $sLandscape, $aProperties); + $o->generateTcpdf($outDocUid, $caseFields, $path, $filename, ' ', $landscape, $properties); libxml_use_internal_errors(false); } else { - $o->generateTcpdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $o->generateTcpdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } break; case 'HTML2PDF': default: - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties, $sApplication); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties, $application); break; } } else { - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } } - //end if $sTypeDocToGener + //end if $typeDocsToGen /* End - Create .pdf */ } else { - return \PEAR::raiseError( + return PEAR::raiseError( null, G_ERROR_USER_UID, null, diff --git a/workflow/engine/src/ProcessMaker/Util/helpers.php b/workflow/engine/src/ProcessMaker/Util/helpers.php index b3d93a2ae..684569b0f 100644 --- a/workflow/engine/src/ProcessMaker/Util/helpers.php +++ b/workflow/engine/src/ProcessMaker/Util/helpers.php @@ -485,6 +485,33 @@ function csrfToken() return isset($_SESSION['USR_CSRF_TOKEN']) ? $_SESSION['USR_CSRF_TOKEN'] : ''; } +/** + * Check if a string is a valid HTML code + * + * @param string $string + * + * @return bool + * + * @see G::replaceDataField() + */ +function stringIsValidHtml($string) +{ + // To validate we use the DOMDocument class + $doc = new DOMDocument('1.0', 'UTF-8'); + + // Clean previous errors + libxml_clear_errors(); + + // This line have to be silenced because if the string is not an HTML a Warning is displayed + @$doc->loadHTML($string); + + // Get last error parsing the HTML + $libXmlError = libxml_get_last_error(); + + // If the attribute "textContent" is empty or exists libxml errors, is not a valid HTML + return $doc->textContent !== '' && empty($libXmlError); +} + // Methods deleted in PHP 7.x, added in this file in order to keep compatibility with old libraries included/used in ProcessMaker if (!function_exists('set_magic_quotes_runtime')) { function set_magic_quotes_runtime($value) {