From b1189a15aeb8edab0dbb8d6984c3bcbec0e7c53b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come.chilliet@fusiondirectory.org>
Date: Wed, 10 Jun 2020 10:36:37 +0200
Subject: [PATCH] :tractor: feat(core) Use custom method htmlescape instead of
 htmlentities

This avoids repeating parameters at each call, and makes sure the same
 parameters are used for escaping across fusiondirectory.
This commit also adds escaping in some places where there was none.

issue #6071
---
 include/class_baseSelector.inc                     |  8 ++++----
 include/class_divSelectBox.inc                     |  2 +-
 include/class_msgPool.inc                          |  6 +++---
 include/class_objects.inc                          |  4 ++--
 include/class_pluglist.inc                         | 12 ++++++------
 include/login/class_LoginMethod.inc                |  2 +-
 include/management/actions/class_Action.inc        |  8 ++++----
 include/management/columns/class_Column.inc        |  2 +-
 .../management/columns/class_ObjectTypeColumn.inc  |  4 ++--
 .../management/columns/class_PropertiesColumn.inc  |  4 ++--
 .../attributes/class_BaseSelectorAttribute.inc     |  2 +-
 .../attributes/class_BooleanAttribute.inc          |  4 ++--
 .../attributes/class_DateAttribute.inc             |  6 +++---
 .../attributes/class_FileAttribute.inc             |  2 +-
 .../simpleplugin/attributes/class_IntAttribute.inc |  6 +++---
 .../attributes/class_SelectAttribute.inc           |  4 ++--
 .../attributes/class_StringAttribute.inc           | 12 ++++++------
 .../attributes/dialog/class_ButtonAttribute.inc    |  2 +-
 .../attributes/dialog/class_ObjectAttribute.inc    |  4 ++--
 include/simpleplugin/class_Attribute.inc           | 14 ++++----------
 include/simpleplugin/class_simplePlugin.inc        |  2 +-
 plugins/admin/groups/class_GroupContentColumn.inc  |  6 +++---
 plugins/admin/users/class_LockAction.inc           |  8 ++++----
 setup/class_setupStepMigrate.inc                   | 12 ++++++------
 24 files changed, 65 insertions(+), 71 deletions(-)

diff --git a/include/class_baseSelector.inc b/include/class_baseSelector.inc
index b16436e4f..c80d81e49 100644
--- a/include/class_baseSelector.inc
+++ b/include/class_baseSelector.inc
@@ -197,7 +197,7 @@ class baseSelector
                   ' onfocus="$(\'bs_'.$this->pid.'\').hide()"'.
                   ' onmouseover="Element.clonePosition($(\'bs_'.$this->pid.'\'), \''.$this->getInputHtmlId().'\', {setHeight: false, setWidth: false, offsetTop:(Element.getHeight(\''.$this->getInputHtmlId().'\'))});$(\'bs_'.$this->pid.'\').show();"'.
                   ' onmouseout="rtimer= Element.hide.delay(0.25, \'bs_'.$this->pid.'\')"'.
-                  ' value="'.htmlentities($this->pathMapping[$this->base], ENT_COMPAT, 'UTF-8').'"/>';
+                  ' value="'.htmlescape($this->pathMapping[$this->base]).'"/>';
 
     // Autocompleter
     $this->tree .= "<div id='autocomplete_".$this->pid."' class='autocomplete'></div>".
@@ -235,7 +235,7 @@ class baseSelector
           $this->tree .= "</li>\n";
           $this->tree .= '<li><a title="'.$parent_base.'">'.
                         '<img class="center" '.
-                        'src="'.htmlentities($departmentInfo[$parent_base]['img'], ENT_COMPAT, 'UTF-8').'" '.
+                        'src="'.htmlescape($departmentInfo[$parent_base]['img']).'" '.
                         'alt=""/>&nbsp;'.
                         $this->escape($departmentInfo[$parent_base]['name']).
                         (($departmentInfo[$parent_base]['description'] == '') ? '' : '&nbsp;<span class="informal">['.$this->escape($departmentInfo[$parent_base]['description']).']</span>').
@@ -252,7 +252,7 @@ class baseSelector
       $link       = "onclick=\"\$('bs_rebase_".$this->pid."').value='".base64_encode($base)."';$('submit_tree_base_".$this->pid."').click();\"";
       $this->tree .= '<li><a'.$selected.' '.$link.' title="'.$base.'">'.
                     '<img class="center" '.
-                    'src="'.htmlentities($departmentInfo[$base]['img'], ENT_COMPAT, 'UTF-8').'" '.
+                    'src="'.htmlescape($departmentInfo[$base]['img']).'" '.
                     'alt=""/>&nbsp;'.
                     $this->escape($departmentInfo[$base]['name']).
                     (($departmentInfo[$base]['description'] == '') ? '' : '&nbsp;<span class="informal">['.$this->escape($departmentInfo[$base]['description']).']</span>').
@@ -288,7 +288,7 @@ class baseSelector
    */
   function escape (string $string): string
   {
-    return str_replace(' ', '&nbsp;', htmlentities($string, ENT_COMPAT, 'UTF-8'));
+    return str_replace(' ', '&nbsp;', htmlescape($string));
   }
 
   /*!
diff --git a/include/class_divSelectBox.inc b/include/class_divSelectBox.inc
index ba6f5116d..2392c4c45 100644
--- a/include/class_divSelectBox.inc
+++ b/include/class_divSelectBox.inc
@@ -196,7 +196,7 @@ class divSelectBox
           if ($s_value2['string'] === '') {
             $s_return .= '&nbsp;';
           } else {
-            $s_return .= htmlentities($s_value2['string'], ENT_COMPAT, 'UTF-8');
+            $s_return .= htmlescape($s_value2['string']);
           }
         } else {
           $s_return .= $s_value2['html'];
diff --git a/include/class_msgPool.inc b/include/class_msgPool.inc
index 7ebb1278b..b190af7ad 100644
--- a/include/class_msgPool.inc
+++ b/include/class_msgPool.inc
@@ -270,12 +270,12 @@ class msgPool
     if (!is_string($data)) {
       $data = var_export($data, TRUE);
     }
-    $error = sprintf(_('The field "%s" contains an invalid value.'), htmlentities($name, ENT_COMPAT, 'UTF-8'));
-    $error .= '<br/><br/> "'.htmlentities($data, ENT_COMPAT, 'UTF-8').'"';
+    $error = htmlescape(sprintf(_('The field "%s" contains an invalid value.'), $name));
+    $error .= '<br/><br/> "'.htmlescape($data).'"';
 
     /* Stylize example */
     if ($example !== '') {
-      $error .= '<br/><br/><i>'.sprintf(_('Example: %s'), htmlentities($example, ENT_COMPAT, 'UTF-8')).'</i> ';
+      $error .= '<br/><br/><i>'.htmlescape(sprintf(_('Example: %s'), $example)).'</i> ';
     }
 
     return $error;
diff --git a/include/class_objects.inc b/include/class_objects.inc
index 4919c543d..590dd34cf 100644
--- a/include/class_objects.inc
+++ b/include/class_objects.inc
@@ -377,10 +377,10 @@ class objects
       $text = $text[$infos['nameAttr']][0];
     }
 
-    $text = htmlentities($text, ENT_COMPAT, 'UTF-8');
+    $text = htmlescape($text);
 
     if ($icon && isset($infos['icon'])) {
-      $text = '<img alt="'.$infos['name'].'" title="'.$dn.'" src="'.htmlentities($infos['icon'], ENT_COMPAT, 'UTF-8').'" class="center"/>&nbsp;'.$text;
+      $text = '<img alt="'.$infos['name'].'" title="'.$dn.'" src="'.htmlescape($infos['icon']).'" class="center"/>&nbsp;'.$text;
     }
 
     if ($link) {
diff --git a/include/class_pluglist.inc b/include/class_pluglist.inc
index c1a838112..0a80246f0 100644
--- a/include/class_pluglist.inc
+++ b/include/class_pluglist.inc
@@ -442,13 +442,13 @@ class pluglist
 
           /* Load icon */
           if (isset($info['CLASS']) && !preg_match("/\//", $plIcon) && !preg_match("/^geticon/", $plIcon)) {
-            $image = get_template_path("plugins/".preg_replace('%^.*/([^/]+)/[^/]+$%', '\1', $class_mapping[$info['CLASS']])."/images/$plIcon");
+            $image = get_template_path('plugins/'.preg_replace('%^.*/([^/]+)/[^/]+$%', '\1', $class_mapping[$info['CLASS']]).'/images/'.$plIcon);
           } else {
-            $image = htmlentities($plIcon, ENT_COMPAT, 'UTF-8');
+            $image = $plIcon;
           }
 
-          $entries  .= '<div class="iconmenu" id="menuitem_icon_'.$id.'" onClick=\'location.href="'.$href.'"\' title="'.$plDescription.'">';
-          $item     = '<div class="imgcontainer"><img src="'.$image.'" alt=""/></div><span>&nbsp;'.$plHeadline.'</span>';
+          $entries  .= '<div class="iconmenu" id="menuitem_icon_'.$id.'" onClick=\'location.href="'.$href.'"\' title="'.htmlescape($plDescription).'">';
+          $item     = '<div class="imgcontainer"><img src="'.htmlescape($image).'" alt=""/></div><span>&nbsp;'.htmlescape($plHeadline).'</span>';
           $entries  .= $item."</div>\n";
         }
 
@@ -588,9 +588,9 @@ class pluglist
     } catch (Exception $e) {
       $smarty->assign('headline', _('Fatal error!'));
       $smarty->assign('headline_image', 'geticon.php?context=status&icon=dialog-error&size=32');
-      $display = '<h1>'._('An unrecoverable error occurred. Please contact your administator.').'</h1><p>';
+      $display = '<h1>'.htmlescape(_('An unrecoverable error occurred. Please contact your administator.')).'</h1><p>';
       if (ini_get('display_errors') == 1) {
-        $display .= nl2br(htmlentities((string)$e, ENT_COMPAT, 'UTF-8'));
+        $display .= nl2br(htmlescape((string)$e));
       } else {
         $display .= 'Error detail display is turned off.';
       }
diff --git a/include/login/class_LoginMethod.inc b/include/login/class_LoginMethod.inc
index 9f4f83bdd..ae7eafa4b 100644
--- a/include/login/class_LoginMethod.inc
+++ b/include/login/class_LoginMethod.inc
@@ -204,7 +204,7 @@ class LoginMethod
     } catch (Exception $e) {
       $display = '<h1>'._('An unrecoverable error occurred. Please contact your administator.').'</h1><p>';
       if (ini_get('display_errors') == 1) {
-        $display .= nl2br(htmlentities((string)$e, ENT_COMPAT, 'UTF-8'));
+        $display .= nl2br(htmlescape((string)$e));
       } else {
         $display .= 'Error detail display is turned off.';
       }
diff --git a/include/management/actions/class_Action.inc b/include/management/actions/class_Action.inc
index 18d283482..bc9244c10 100644
--- a/include/management/actions/class_Action.inc
+++ b/include/management/actions/class_Action.inc
@@ -209,13 +209,13 @@ class Action
     }
 
     if (!$this->isEnabledFor($entry)) {
-      return '<img src="'.htmlentities($this->icon.'&disabled=1', ENT_COMPAT, 'UTF-8').'"'.
-              ' title="'.$this->label.'" alt="'.$this->label.'"/>';
+      return '<img src="'.htmlescape($this->icon.'&disabled=1').'"'.
+              ' title="'.htmlescape($this->label).'" alt="'.htmlescape($this->label).'"/>';
     }
 
     // Render
-    return '<input type="image" src="'.htmlentities($this->icon, ENT_COMPAT, 'UTF-8').'"'.
-            ' title="'.$this->label.'" alt="'.$this->label.'" name="listing_'.$this->name.'_'.$entry->row.'"/>';
+    return '<input type="image" src="'.htmlescape($this->icon).'"'.
+            ' title="'.htmlescape($this->label).'" alt="'.htmlescape($this->label).'" name="listing_'.$this->name.'_'.$entry->row.'"/>';
   }
 
   function isEnabledFor (ListingEntry $entry = NULL): bool
diff --git a/include/management/columns/class_Column.inc b/include/management/columns/class_Column.inc
index 3fa4e89bf..f40ce0b4f 100644
--- a/include/management/columns/class_Column.inc
+++ b/include/management/columns/class_Column.inc
@@ -188,7 +188,7 @@ class Column
 
   protected function renderSingleValue (ListingEntry $entry, string $value): string
   {
-    return htmlentities($value, ENT_COMPAT, 'UTF-8');
+    return htmlescape($value);
   }
 
   function getRawExportValues (ListingEntry $entry): array
diff --git a/include/management/columns/class_ObjectTypeColumn.inc b/include/management/columns/class_ObjectTypeColumn.inc
index 21b3b9914..0d7a9820a 100644
--- a/include/management/columns/class_ObjectTypeColumn.inc
+++ b/include/management/columns/class_ObjectTypeColumn.inc
@@ -32,10 +32,10 @@ class ObjectTypeColumn extends Column
   {
     if ($entry->isTemplate()) {
       $infos = objects::infos($entry->getTemplatedType());
-      return '<img title="'.$entry->dn.'" src="'.htmlentities('geticon.php?context=devices&icon=template&size=16', ENT_COMPAT, 'UTF-8').'" alt="'.sprintf(_('%s template'), $infos['name']).'"/>';
+      return '<img title="'.htmlescape($entry->dn).'" src="'.htmlescape('geticon.php?context=devices&icon=template&size=16').'" alt="'.htmlescape(sprintf(_('%s template'), $infos['name'])).'"/>';
     } elseif ($entry->type) {
       $infos = objects::infos($entry->type);
-      return '<img title="'.$entry->dn.'" src="'.htmlentities($infos['icon'], ENT_COMPAT, 'UTF-8').'" alt="'.$infos['name'].'"/>';
+      return '<img title="'.htmlescape($entry->dn).'" src="'.htmlescape($infos['icon']).'" alt="'.htmlescape($infos['name']).'"/>';
     } else {
       return '&nbsp;';
     }
diff --git a/include/management/columns/class_PropertiesColumn.inc b/include/management/columns/class_PropertiesColumn.inc
index 8f3d2ddcc..21fcea1ff 100644
--- a/include/management/columns/class_PropertiesColumn.inc
+++ b/include/management/columns/class_PropertiesColumn.inc
@@ -64,8 +64,8 @@ class PropertiesColumn extends Column
       if (empty($tabInfo['icon'])) {
         $result .= '<img src="images/empty.png" alt="" class="optional '.$tabInfo['tab'].'"/>';
       } else {
-        $result .= '<input type="image" src="'.htmlentities($tabInfo['icon'], ENT_COMPAT, 'UTF-8').'" '.
-                    'alt="'.htmlentities($tabInfo['title'], ENT_COMPAT, 'UTF-8').'" title="'.htmlentities($tabInfo['title'], ENT_COMPAT, 'UTF-8').'" '.
+        $result .= '<input type="image" src="'.htmlescape($tabInfo['icon']).'" '.
+                    'alt="'.htmlescape($tabInfo['title']).'" title="'.htmlescape($tabInfo['title']).'" '.
                     'name="listing_edit_tab_'.$tabInfo['tab'].'_'.$entry->row.'"/>';
       }
     }
diff --git a/include/simpleplugin/attributes/class_BaseSelectorAttribute.inc b/include/simpleplugin/attributes/class_BaseSelectorAttribute.inc
index 85ca29185..8a327b657 100644
--- a/include/simpleplugin/attributes/class_BaseSelectorAttribute.inc
+++ b/include/simpleplugin/attributes/class_BaseSelectorAttribute.inc
@@ -150,7 +150,7 @@ class BaseSelectorAttribute extends Attribute
       $display = $this->renderInputField(
         'text', '',
         [
-          'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+          'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
         ]
       );
     } else {
diff --git a/include/simpleplugin/attributes/class_BooleanAttribute.inc b/include/simpleplugin/attributes/class_BooleanAttribute.inc
index 855b02e1f..271516643 100644
--- a/include/simpleplugin/attributes/class_BooleanAttribute.inc
+++ b/include/simpleplugin/attributes/class_BooleanAttribute.inc
@@ -105,10 +105,10 @@ class BooleanAttribute extends Attribute
     $attributes = ($this->value ? ['checked' => 'checked'] : []);
     if ($this->submitForm) {
       $js       = 'document.mainform.submit();';
-      $attributes['onChange'] = 'javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8');
+      $attributes['onChange'] = 'javascript:'.htmlescape($js);
     } elseif (!empty($this->managedAttributes)) {
       $js       = $this->managedAttributesJS();
-      $attributes['onChange'] = 'javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8');
+      $attributes['onChange'] = 'javascript:'.htmlescape($js);
     }
     $display  = $this->renderInputField('checkbox', $id, $attributes);
     return $this->renderAcl($display);
diff --git a/include/simpleplugin/attributes/class_DateAttribute.inc b/include/simpleplugin/attributes/class_DateAttribute.inc
index 8796696f6..e7db0007f 100644
--- a/include/simpleplugin/attributes/class_DateAttribute.inc
+++ b/include/simpleplugin/attributes/class_DateAttribute.inc
@@ -166,7 +166,7 @@ class DateAttribute extends Attribute
   function renderFormInput (): string
   {
     $attributes = [
-      'value'   => '{literal}'.$this->getValue().'{/literal}',
+      'value'   => '{literal}'.htmlescape($this->getValue()).'{/literal}',
       'pattern' => '{literal}[0-9]{4}-[0-9]{2}-[0-9]{2}{/literal}',
     ];
     if ($this->minDate !== NULL) {
@@ -183,7 +183,7 @@ class DateAttribute extends Attribute
   {
     $id = $this->getHtmlId();
     $attributes = [
-      'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+      'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
     ];
     if ($this->isSubAttribute) {
       $attributes['class'] = 'subattribute';
@@ -357,7 +357,7 @@ class GeneralizedTimeDisplayAttribute extends GeneralizedTimeDateAttribute
   {
     $date = $this->getDateValue();
     $date->setTimezone(timezone::getDefaultTimeZone());
-    return htmlentities($date->format('Y-m-d, H:i:s'), ENT_COMPAT, 'UTF-8');
+    return htmlescape($date->format('Y-m-d, H:i:s'));
   }
 }
 
diff --git a/include/simpleplugin/attributes/class_FileAttribute.inc b/include/simpleplugin/attributes/class_FileAttribute.inc
index 0be6a09e8..7f9fe1690 100644
--- a/include/simpleplugin/attributes/class_FileAttribute.inc
+++ b/include/simpleplugin/attributes/class_FileAttribute.inc
@@ -272,7 +272,7 @@ class FileTextAreaAttribute extends FileDownloadAttribute
     $id = $this->getHtmlId();
     $display  = '<textarea name="'.$id.'_text" id="'.$id.'_text"'.
                 ($this->disabled ? 'disabled="disabled"' : '').'>'.
-                '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}</textarea><br/>';
+                '{literal}'.htmlescape($this->getValue()).'{/literal}</textarea><br/>';
     return $this->renderAcl($display).parent::renderFormInput();
   }
 
diff --git a/include/simpleplugin/attributes/class_IntAttribute.inc b/include/simpleplugin/attributes/class_IntAttribute.inc
index e3252a8cc..9f9d28bd1 100644
--- a/include/simpleplugin/attributes/class_IntAttribute.inc
+++ b/include/simpleplugin/attributes/class_IntAttribute.inc
@@ -105,7 +105,7 @@ class IntAttribute extends Attribute
   {
     $id = $this->getHtmlId();
     $attributes = [
-      'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+      'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
     ];
     if ($this->min !== FALSE) {
       $attributes['min'] = $this->min;
@@ -118,7 +118,7 @@ class IntAttribute extends Attribute
     }
     if (!empty($this->managedAttributes)) {
       $js       = $this->managedAttributesJS();
-      $attributes['onChange'] = 'javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8');
+      $attributes['onChange'] = 'javascript:'.htmlescape($js);
     }
     if ($this->isSubAttribute) {
       $attributes['class'] = 'subattribute';
@@ -133,7 +133,7 @@ class IntAttribute extends Attribute
   {
     $id = $this->getHtmlId();
     $attributes = [
-      'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+      'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
     ];
     if ($this->isSubAttribute) {
       $attributes['class'] = 'subattribute';
diff --git a/include/simpleplugin/attributes/class_SelectAttribute.inc b/include/simpleplugin/attributes/class_SelectAttribute.inc
index 4551557cd..a7a8a971b 100644
--- a/include/simpleplugin/attributes/class_SelectAttribute.inc
+++ b/include/simpleplugin/attributes/class_SelectAttribute.inc
@@ -206,10 +206,10 @@ class SelectAttribute extends Attribute
     }
     if ($this->submitForm) {
       $js       = 'document.mainform.submit();';
-      $display  .= 'onChange="javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8').'"';
+      $display  .= 'onChange="javascript:'.htmlescape($js).'"';
     } elseif (!empty($this->managedAttributes)) {
       $js       = $this->managedAttributesJS();
-      $display  .= 'onChange="javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8').'"';
+      $display  .= 'onChange="javascript:'.htmlescape($js).'"';
     }
     if ($this->isSubAttribute) {
       $display .= 'class="subattribute" ';
diff --git a/include/simpleplugin/attributes/class_StringAttribute.inc b/include/simpleplugin/attributes/class_StringAttribute.inc
index 4a3aec48e..c192092e7 100644
--- a/include/simpleplugin/attributes/class_StringAttribute.inc
+++ b/include/simpleplugin/attributes/class_StringAttribute.inc
@@ -75,17 +75,17 @@ class StringAttribute extends Attribute
   {
     $id = $this->getHtmlId();
     $attributes = [
-      'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+      'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
     ];
     if (!empty($this->managedAttributes)) {
       $js       = $this->managedAttributesJS();
-      $attributes['onChange'] = 'javascript:'.htmlentities($js, ENT_COMPAT, 'UTF-8');
+      $attributes['onChange'] = 'javascript:'.htmlescape($js);
     }
     if ($this->autocomplete !== NULL) {
       $attributes['autocomplete'] = $this->autocomplete;
     }
     if ($this->html5pattern !== NULL) {
-      $attributes['pattern'] = '{literal}'.htmlentities($this->html5pattern, ENT_COMPAT, 'UTF-8').'{/literal}';
+      $attributes['pattern'] = '{literal}'.htmlescape($this->html5pattern).'{/literal}';
     }
     if ($this->isSubAttribute) {
       $attributes['class'] = 'subattribute';
@@ -100,7 +100,7 @@ class StringAttribute extends Attribute
   {
     $id = $this->getHtmlId();
     $attributes = [
-      'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+      'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
     ];
     if ($this->autocomplete !== NULL) {
       $attributes['autocomplete'] = $this->autocomplete;
@@ -191,7 +191,7 @@ class TextAreaAttribute extends StringAttribute
                 ($this->disabled ? ' disabled="disabled"' : '').
                 ($this->isSubAttribute ? ' class="subattribute"' : ($this->isRequired() ? ' required="required"' : '')).
                 '>'.
-                '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}</textarea>';
+                '{literal}'.htmlescape($this->getValue()).'{/literal}</textarea>';
     return $this->renderAcl($display);
   }
 
@@ -202,7 +202,7 @@ class TextAreaAttribute extends StringAttribute
                 ($this->disabled ? ' disabled="disabled"' : '').
                 ($this->isSubAttribute ? ' class="subattribute"' : '').
                 '>'.
-                '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}</textarea>';
+                '{literal}'.htmlescape($this->getValue()).'{/literal}</textarea>';
     return $this->renderAcl($display);
   }
 }
diff --git a/include/simpleplugin/attributes/dialog/class_ButtonAttribute.inc b/include/simpleplugin/attributes/dialog/class_ButtonAttribute.inc
index abdfe8a5e..3cc870bdd 100644
--- a/include/simpleplugin/attributes/dialog/class_ButtonAttribute.inc
+++ b/include/simpleplugin/attributes/dialog/class_ButtonAttribute.inc
@@ -41,7 +41,7 @@ class ButtonAttribute extends Attribute
     $id = $this->getHtmlId();
     $display = $this->renderInputField(
       'submit', $id,
-      ['value' => '{literal}'.htmlentities($this->buttonText, ENT_COMPAT, 'UTF-8').'{/literal}']
+      ['value' => '{literal}'.htmlescape($this->buttonText).'{/literal}']
     );
     return $this->renderAcl($display);
   }
diff --git a/include/simpleplugin/attributes/dialog/class_ObjectAttribute.inc b/include/simpleplugin/attributes/dialog/class_ObjectAttribute.inc
index c3de71f7a..45f22fbae 100644
--- a/include/simpleplugin/attributes/dialog/class_ObjectAttribute.inc
+++ b/include/simpleplugin/attributes/dialog/class_ObjectAttribute.inc
@@ -88,11 +88,11 @@ class ObjectAttribute extends DialogButtonAttribute
       $display = $this->renderInputField(
         'text', $id,
         [
-          'value' => '{literal}'.htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8').'{/literal}'
+          'value' => '{literal}'.htmlescape($this->getValue()).'{/literal}'
         ]
       );
     } else {
-      $display  = '<img src="'.htmlentities($infos['icon'], ENT_COMPAT, 'UTF-8').'" alt="'.$infos['name'].'" class="center"/>';
+      $display  = '<img src="'.htmlescape($infos['icon']).'" alt="'.$infos['name'].'" class="center"/>';
       if ($this->getValue() == '') {
         $display  .= '<b>'._('None').'</b>';
       } elseif ($this->buttonText === NULL) {
diff --git a/include/simpleplugin/class_Attribute.inc b/include/simpleplugin/class_Attribute.inc
index e03f20ef6..07bfa17b2 100644
--- a/include/simpleplugin/class_Attribute.inc
+++ b/include/simpleplugin/class_Attribute.inc
@@ -619,15 +619,9 @@ class Attribute
       if ($readOnly) {
         $currentValue = $this->getValue();
         if (is_array($currentValue)) {
-          $input = '{literal}'.implode('<br/>', array_map(
-            function ($v)
-            {
-              return htmlentities($v, ENT_COMPAT, 'UTF-8');
-            },
-            $currentValue
-          )).'{/literal}';
+          $input = '{literal}'.implode('<br/>', array_map('htmlescape', $currentValue)).'{/literal}';
         } else {
-          $input = '{literal}'.htmlentities($currentValue, ENT_COMPAT, 'UTF-8').'{/literal}';
+          $input = '{literal}'.htmlescape($currentValue).'{/literal}';
         }
       } elseif ($this->isTemplate()) {
         $input = $this->renderTemplateInput();
@@ -887,7 +881,7 @@ class DisplayLDAPAttribute extends Attribute
     if ($this->allowHTML) {
       $value = $this->getValue();
     } else {
-      $value = htmlentities($this->getValue(), ENT_COMPAT, 'UTF-8');
+      $value = htmlescape($this->getValue());
     }
     if ($this->allowSmarty) {
       return $value;
@@ -940,7 +934,7 @@ class DisplayLDAPArrayAttribute extends Attribute
     if (is_array($value)) {
       $value = join(', ', $value);
     }
-    return '{literal}'.htmlentities($value, ENT_COMPAT, 'UTF-8').'{/literal}';
+    return '{literal}'.htmlescape($value).'{/literal}';
   }
 }
 
diff --git a/include/simpleplugin/class_simplePlugin.inc b/include/simpleplugin/class_simplePlugin.inc
index 0baa4b309..f4b7b5e65 100644
--- a/include/simpleplugin/class_simplePlugin.inc
+++ b/include/simpleplugin/class_simplePlugin.inc
@@ -878,7 +878,7 @@ class simplePlugin implements SimpleTab
       $legend = $sectionInfo['name'];
       if (isset($sectionInfo['icon'])) {
         $legend = '<img '.
-                  'src="'.htmlentities($sectionInfo['icon'], ENT_COMPAT, 'UTF-8').'" '.
+                  'src="'.htmlescape($sectionInfo['icon']).'" '.
                   'alt="" '.
                   '/>'.$legend;
       }
diff --git a/plugins/admin/groups/class_GroupContentColumn.inc b/plugins/admin/groups/class_GroupContentColumn.inc
index 7b6f2db6f..1731c6274 100644
--- a/plugins/admin/groups/class_GroupContentColumn.inc
+++ b/plugins/admin/groups/class_GroupContentColumn.inc
@@ -41,9 +41,9 @@ class GroupContentColumn extends Column
       }
       try {
         $infos  = objects::infos(ogroup::$objectTypes[$types[$i]]);
-        $result .= '<img src="'.htmlentities($infos['icon'], ENT_COMPAT, 'UTF-8').'"'.
-                    ' alt="'.htmlentities($infos['name'], ENT_COMPAT, 'UTF-8').'"'.
-                    ' title="'.htmlentities($infos['name'], ENT_COMPAT, 'UTF-8').'"/>';
+        $result .= '<img src="'.htmlescape($infos['icon']).'"'.
+                    ' alt="'.htmlescape($infos['name']).'"'.
+                    ' title="'.htmlescape($infos['name']).'"/>';
       } catch (NonExistingObjectTypeException $e) {
         continue;
       }
diff --git a/plugins/admin/users/class_LockAction.inc b/plugins/admin/users/class_LockAction.inc
index 5007d0b99..632a13bec 100644
--- a/plugins/admin/users/class_LockAction.inc
+++ b/plugins/admin/users/class_LockAction.inc
@@ -93,11 +93,11 @@ class LockAction extends Action
       return '<img src="images/empty.png" alt=" " class="center optional"/>';
     } elseif ($lockStatus) {
       // Render
-      return '<input type="image" src="'.htmlentities($this->icon['lock'], ENT_COMPAT, 'UTF-8').'"'.
-              ' title="'.$this->label['unlock'].'" alt="'.$this->label['unlock'].'" name="listing_'.$this->name.'_unlock_'.$entry->row.'"/>';
+      return '<input type="image" src="'.htmlescape($this->icon['lock']).'"'.
+              ' title="'.htmlescape($this->label['unlock']).'" alt="'.htmlescape($this->label['unlock']).'" name="listing_'.$this->name.'_unlock_'.$entry->row.'"/>';
     } else {
-      return '<input type="image" src="'.htmlentities($this->icon['unlock'], ENT_COMPAT, 'UTF-8').'"'.
-              ' title="'.$this->label['lock'].'" alt="'.$this->label['lock'].'" name="listing_'.$this->name.'_lock_'.$entry->row.'"/>';
+      return '<input type="image" src="'.htmlescape($this->icon['unlock']).'"'.
+              ' title="'.htmlescape($this->label['lock']).'" alt="'.htmlescape($this->label['lock']).'" name="listing_'.$this->name.'_lock_'.$entry->row.'"/>';
     }
   }
 }
diff --git a/setup/class_setupStepMigrate.inc b/setup/class_setupStepMigrate.inc
index 111f90455..b350efdfe 100644
--- a/setup/class_setupStepMigrate.inc
+++ b/setup/class_setupStepMigrate.inc
@@ -779,7 +779,7 @@ class setupStepMigrate extends setupStep
                 $ldap->cat($member, ['dn','uid','cn','memberUid','roleOccupant','objectClass']);
                 if ($member_attrs = $ldap->fetch()) {
                   if (in_array('inetOrgPerson', $member_attrs['objectClass'])) {
-                    $valid_users[]  = htmlentities(($member_attrs['uid'][0] ?? $member_attrs['dn']), ENT_COMPAT, 'UTF-8');
+                    $valid_users[]  = htmlescape(($member_attrs['uid'][0] ?? $member_attrs['dn']));
                     $FD_admin_found = TRUE;
                   } elseif (in_array('posixGroup', $member_attrs['objectClass'])) {
                     $val_users = [];
@@ -787,12 +787,12 @@ class setupStepMigrate extends setupStep
                       for ($e = 0; $e < $member_attrs['memberUid']['count']; $e++) {
                         $ldap->search('(&(objectClass=inetOrgPerson)(uid='.ldap_escape_f($member_attrs['memberUid'][$e]).'))', ['uid','dn']);
                         if ($user_attrs = $ldap->fetch()) {
-                          $val_users[] = htmlentities(($user_attrs['uid'][0] ?? $user_attrs['dn']), ENT_COMPAT, 'UTF-8');
+                          $val_users[] = htmlescape(($user_attrs['uid'][0] ?? $user_attrs['dn']));
                         }
                       }
                     }
                     if (!empty($val_users)) {
-                      $valid_groups[] = htmlentities($member_attrs['cn'][0], ENT_COMPAT, 'UTF-8').'(<i>'.implode(', ', $val_users).'</i>)';
+                      $valid_groups[] = htmlescape($member_attrs['cn'][0]).'(<i>'.implode(', ', $val_users).'</i>)';
                       $FD_admin_found = TRUE;
                     }
                   } elseif (in_array('organizationalRole', $member_attrs['objectClass'])) {
@@ -801,12 +801,12 @@ class setupStepMigrate extends setupStep
                       for ($e = 0; $e < $member_attrs['roleOccupant']['count']; $e ++) {
                         $ldap->cat($member_attrs['roleOccupant'][$e], ['uid','dn'], '(objectClass=inetOrgPerson)');
                         if ($user_attrs = $ldap->fetch()) {
-                          $val_users[] = htmlentities(($user_attrs['uid'][0] ?? $user_attrs['dn']), ENT_COMPAT, 'UTF-8');
+                          $val_users[] = htmlescape(($user_attrs['uid'][0] ?? $user_attrs['dn']));
                         }
                       }
                     }
                     if (!empty($val_users)) {
-                      $valid_roles[]  = htmlentities($member_attrs['cn'][0], ENT_COMPAT, 'UTF-8').'(<i>'.implode(', ', $val_users).'</i>)';
+                      $valid_roles[]  = htmlescape($member_attrs['cn'][0]).'(<i>'.implode(', ', $val_users).'</i>)';
                       $FD_admin_found = TRUE;
                     }
                   }
@@ -1161,7 +1161,7 @@ class setupStepMigrate extends setupStep
           $dn   = $object['dn'];
           $d_dn = preg_replace('/,.*$/', ','.$destination_dep, $dn);
           if ($only_ldif) {
-            $object['ldif'] = sprintf(_("Entry will be moved from:<br/>\t%s<br/>to:<br/>\t%s"), htmlentities($dn, ENT_COMPAT, 'UTF-8'), htmlentities($d_dn, ENT_COMPAT, 'UTF-8'));
+            $object['ldif'] = nl2br(htmlescape(sprintf(_("Entry will be moved from:\n\t%s\nto:\n\t%s"), $dn, $d_dn)));
 
             /* Check if there are references to this object */
             $ldap->search('(&(member='.ldap_escape_f($dn).')(|(objectClass=gosaGroupOfNames)(objectClass=groupOfNames)))', ['dn']);
-- 
GitLab