diff --git a/application/dashlet.class.inc.php b/application/dashlet.class.inc.php index a298a5069..43b06b666 100644 --- a/application/dashlet.class.inc.php +++ b/application/dashlet.class.inc.php @@ -667,7 +667,7 @@ class DashletUnknown extends Dashlet */ public function GetPropertiesFields(DesignerForm $oForm) { - $oField = new DesignerLongTextField('xml', Dict::S('UI:DashletUnknown:Prop-XMLConfiguration'), $this->sOriginalDashletXML); + $oField = new DesignerXMLField('xml', Dict::S('UI:DashletUnknown:Prop-XMLConfiguration'), $this->sOriginalDashletXML); $oForm->AddField($oField); } diff --git a/application/forms.class.inc.php b/application/forms.class.inc.php index 889efe04d..ec952e0a3 100644 --- a/application/forms.class.inc.php +++ b/application/forms.class.inc.php @@ -1110,13 +1110,41 @@ $('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', } EOF ); - $sValue = ""; + $sValue = ""; } else { - $sValue = "
".utils::EscapeHtml($this->defaultValue)."
"; + $sValue = "
".$this->PrepareValueForRendering()."
"; } return array('label' => $this->sLabel, 'value' => $sValue); } + + /** + * @return string|null The value itself as expected for rendering. May it be encoded, escaped or else. + * @since 3.1.0 N°6405 + */ + protected function PrepareValueForRendering(): ?string + { + return utils::EscapeHtml($this->defaultValue); + } +} + +/** + * Class DesignerXMLField + * + * Field to display XML content + * + * @author Guillaume Lajarige + * @since 3.1.0 N°6405 + */ +class DesignerXMLField extends DesignerLongTextField +{ + /** + * @inheritDoc + */ + protected function PrepareValueForRendering(): ?string + { + return utils::EscapeHtml($this->defaultValue, true); + } } class DesignerIntegerField extends DesignerFormField diff --git a/application/utils.inc.php b/application/utils.inc.php index 87e4f7dc0..575da4fa1 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -1970,6 +1970,7 @@ SQL; /** * @param string $sValue + * @param bool $bDoubleEncode Whether to double encode the value or not * * @return string passed value with only characters having a special meaning in HTML escaped as entities * Since 3.0.0 we were using for this {@link HtmlEntities} but it was overkill and leads to double escaping ! @@ -1977,14 +1978,15 @@ SQL; * @uses \htmlspecialchars() * @link https://www.php.net/manual/fr/function.htmlspecialchars.php * @since 3.0.0 N°3623 + * @since 3.1.0 N°6405 Add $bDoubleEncode parameter */ - public static function EscapeHtml($sValue) + public static function EscapeHtml($sValue, bool $bDoubleEncode = false) { return htmlspecialchars( $sValue ?? '', ENT_QUOTES | ENT_DISALLOWED | ENT_HTML5, WebPage::PAGES_CHARSET, - false + $bDoubleEncode ); } diff --git a/tests/php-unit-tests/unitary-tests/application/DesignerFormFieldTest.php b/tests/php-unit-tests/unitary-tests/application/DesignerFormFieldTest.php new file mode 100644 index 000000000..eae8975eb --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/DesignerFormFieldTest.php @@ -0,0 +1,82 @@ + + * + */ + +namespace Combodo\iTop\Test\UnitTest\Application; + +use Combodo\iTop\Test\UnitTest\ItopTestCase; +use DesignerXMLField; +use utils; + +/** + * @covers DesignerFormField + */ +class DesignerFormFieldTest extends ItopTestCase +{ + /** + * @param string $sFieldFQCN + * @param string $sInputValue + * @param string $sExpectedValue + * + * @return void + * @throws \ReflectionException + * @covers DesignerLongTextField::PrepareValueForRendering + * @dataProvider PrepareValueForRenderingProvider + */ + public function testPrepareValueForRendering(string $sFieldFQCN, string $sInputValue, string $sExpectedValue) + { + $oField = new $sFieldFQCN('field_code', 'Field label', $sInputValue); + + $sTestedValue = $this->InvokeNonPublicMethod($sFieldFQCN, 'PrepareValueForRendering', $oField, []); + $this->assertEquals($sExpectedValue, $sTestedValue); + } + + public function PrepareValueForRenderingProvider(): array + { + return [ + 'DesignerLongTextField should not double encode XML' => [ + '\\DesignerLongTextField', + << + Foo & Bar + +XML, + << [ + '\\DesignerXMLField', + << + Foo & Bar + +XML, + << ['abcdefghijklmnop', null], '&' => ['abcdefghijklmnop&0123456789', 'abcdefghijklmnop&0123456789'], - ['"double quotes"', '"double quotes"'], - ["'simple quotes'", ''simple quotes''], + 'double quotes' => ['"double quotes"', '"double quotes"'], + 'simple quotes' => ["'simple quotes'", ''simple quotes''], + 'no double encode' => [ + 'Foo & Bar', + '<root><title>Foo & Bar</title></root>' + ], + 'double encode forced (for XML mostly)' => [ + 'Foo & Bar', + '<root><title>Foo &amp; Bar</title></root>', + true + ], ]; } }