Package: phpldapadmin
Version: 1.2.6.3-0.2
Severity: important
Control: -1 patch
Control: forwarded 1009117 
https://github.com/leenooks/phpLDAPadmin/commit/34d4f2022214780f93e17a5c8dba15cabc8b82b0
Control: fixed 1009117 phpldapadmin/1.2.6.3-0.1

On phpldapadmin, you can not login.
Here is attached all the patches you need to apply.
The final one "Fix-ldap-connect-PHP-8.1-is-now-a-class.patch" makes this bug 
report more true than ever.

Please remove the 149.patch, it's a bundle of patches.
And import all my attachements, I sorted this out and applied DEP-3 headers.

--
William Desportes
From: Patrick Monnerat <patr...@monnerat.net>
Date: Sat, 18 Mar 2023 16:28:44 +0100
Subject: Fix class name Attribute to PLAAttribute because of PHP8 class name
 clash

It has been introduced when class Attribute has been renamed
to PLAAttribute to avoid a name clash with the built-in
class of PHP 8.

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/c90dc06af20b4ec549e43b2b90c018ba0f030cad

Ref: https://www.php.net/manual/en/class.attribute.php
---
 lib/Attribute.php            | 917 -------------------------------------------
 lib/AttributeFactory.php     |   2 +-
 lib/BinaryAttribute.php      |   2 +-
 lib/DateAttribute.php        |   2 +-
 lib/DnAttribute.php          |   2 +-
 lib/GidAttribute.php         |   2 +-
 lib/MultiLineAttribute.php   |   2 +-
 lib/ObjectClassAttribute.php |   2 +-
 lib/PLAAttribute.php         | 917 +++++++++++++++++++++++++++++++++++++++++++
 lib/PasswordAttribute.php    |   2 +-
 lib/SelectionAttribute.php   |   2 +-
 lib/ShadowAttribute.php      |   2 +-
 lib/Visitor.php              |  24 +-
 13 files changed, 941 insertions(+), 937 deletions(-)
 delete mode 100644 lib/Attribute.php
 create mode 100644 lib/PLAAttribute.php

diff --git a/lib/Attribute.php b/lib/Attribute.php
deleted file mode 100644
index 3d040db..0000000
--- a/lib/Attribute.php
+++ /dev/null
@@ -1,917 +0,0 @@
-<?php
-/**
- * Classes and functions for the template engine.
- *
- * @author The phpLDAPadmin development team
- * @package phpLDAPadmin
- */
-
-/**
- * Represents an attribute of a template.
- *
- * @package phpLDAPadmin
- * @subpackage Templates
- */
-class Attribute {
-	# Attribute Name
-	public $name;
-	# Source of this attribute definition
-	protected $source;
-
-	# Current and Old Values
-	protected $oldvalues = array();
-	protected $values = array();
-
-	# MIN/MAX number of values
-	protected $min_value_count = -1;
-	protected $max_value_count = -1;
-
-	# Is the attribute internal
-	protected $internal = false;
-	# Has the attribute been modified
-	protected $modified = false;
-	# Is the attribute being deleted because of an object class removal
-	protected $forcedelete = false;
-	# Is the attribute visible
-	protected $visible = false;
-	protected $forcehide = false;
-	# Is the attribute modifiable
-	protected $readonly = false;
-	# LDAP attribute type MUST/MAY
-	protected $ldaptype = null;
-	# Attribute property type (eg password, select, multiselect)
-	protected $type = '';
-	# Attribute value to keep unique
-	protected $unique = false;
-
-	# Display parameters
-	protected $display = '';
-	protected $icon = '';
-	protected $hint = '';
-	# Helper details
-	protected $helper = array();
-	protected $helpervalue = array();
-	# Onchange details
-	protected $onchange = array();
-	# Show spacer after this attribute is rendered
-	protected $spacer = false;
-	protected $verify = false;
-
-	# Component size
-	protected $size = 0;
-	# Value max length
-	protected $maxlength = 0;
-	# Text Area sizings
-	protected $cols = 0;
-	protected $rows = 0;
-
-	# Public for sorting
-	public $page = 1;
-	public $order = 255;
-	public $ordersort = 255;
-	public $rdn = false;
-
-	# Schema Aliases for this attribute (stored in lowercase)
-	protected $aliases = array();
-
-	# Configuration for automatically generated values
-	protected $autovalue = array();
-	protected $postvalue = array();
-
-	public function __construct($name,$values,$server_id,$source=null) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$server = $_SESSION[APPCONFIG]->getServer($server_id);
-
-		$sattr = $server->getSchemaAttribute($name);
-		if ($sattr) {
-			$this->name = $sattr->getName(false);
-			$this->setLDAPdetails($sattr);
-
-		} else
-			$this->name = $name;
-
-		$this->source = $source;
-
-		# XML attributes are shown by default
-		switch ($source) {
-			case 'XML': $this->show();
-				$this->setXML($values);
-
-				break;
-
-			default:
-				if (! isset($values['values']))
-					debug_dump_backtrace('no index "values"',1);
-
-				$this->initValue($values['values']);
-		}
-
-		# Should this attribute be hidden
-		if ($server->isAttrHidden($this->name))
-			$this->forcehide = true;
-
-		# Should this attribute value be read only
-		if ($server->isAttrReadOnly($this->name))
-			$this->readonly = true;
-
-		# Should this attribute value be unique
-		if ($server->isAttrUnique($this->name))
-			$this->unique = true;
-	}
-
-	/**
-	 * Return the name of the attribute.
-	 *
-	 * @param boolean $lower - Return the attribute in normal or lower case (default lower)
-	 * @param boolean $real - Return the real attribute name (with ;binary, or just the name)
-	 * @return string Attribute name
-	 */
-	public function getName($lower=true,$real=false) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
-
-		if ($real)
-			return $lower ? strtolower($this->name) : $this->name;
-		else
-			return $lower ? strtolower($this->real_attr_name()) : $this->real_attr_name();
-	}
-
-	public function getValues() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->values);
-
-		return $this->values;
-	}
-
-	public function getOldValues() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->oldvalues);
-
-		return $this->oldvalues;
-	}
-
-	public function getValueCount() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->values);
-
-		return count($this->values);
-	}
-
-	public function getSource() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->source);
-
-		return $this->source;
-	}
-
-	/**
-	 * Autovalue is called after the attribute is initialised, and thus the values from the ldap server will be set.
-	 */
-	public function autoValue($new_val) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->values)
-			return;
-
-		$this->values = $new_val;
-	}
-
-	public function initValue($new_val) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->values || $this->oldvalues) {
-			debug_dump(array('new_val'=>$new_val,'this'=>$this));
-			debug_dump_backtrace('new and/or old values are set',1);
-		}
-
-		$this->values = $new_val;
-	}
-
-	public function clearValue() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->values = array();
-	}
-
-	public function setOldValue($val) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->oldvalues = $val;
-	}
-
-	public function setValue($new_val) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->values) {
-			if ($this->values == $new_val)
-				return;
-
-			if ($this->oldvalues) {
-				debug_dump($this);
-				debug_dump_backtrace('old values are set',1);
-			} else
-				$this->oldvalues = $this->values;
-		}
-
-		if ($new_val == $this->values)
-			return;
-
-		$this->values = $new_val;
-		$this->justModified();
-	}
-
-	public function addValue($new_val,$i=-1) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($i < 0)
-			$i = $this->getValueCount();
-
-		$old_val = $this->getValue($i);
-		if (is_null($old_val) || ($old_val != $new_val))
-			$this->justModified();
-
-		$this->values[$i] = $new_val;
-	}
-
-	public function delValue($i=-1) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($i < 0)
-			$this->setValue(array());
-
-		if (! $this->hasBeenModified())
-			$this->oldvalues = $this->values;
-
-		if (isset($this->values[$i])) {
-			unset($this->values[$i]);
-			$this->values = array_values($this->values);
-			$this->justModified();
-		}
-	}
-
-	public function getValue($i, $default=null) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if (isset($this->values[$i]))
-			return $this->values[$i];
-		else
-			return $default;
-	}
-
-	public function getOldValue($i) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if (isset($this->oldvalues[$i]))
-			return $this->oldvalues[$i];
-		else
-			return null;
-	}
-
-	public function getMinValueCount() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->min_value_count);
-
-		return $this->min_value_count;
-	}
-
-	public function setMinValueCount($min) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->min_value_count = $min;
-	}
-
-	public function getMaxValueCount() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->max_value_count);
-
-		return $this->max_value_count;
-	}
-
-	public function setMaxValueCount($max) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->max_value_count = $max;
-	}
-
-	public function haveMoreValues() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->getMaxValueCount() < 0 || ($this->getValueCount() < $this->getMaxValueCount()))
-			return true;
-		else
-			return false;
-	}
-
-	public function justModified() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->modified = true;
-	}
-
-	public function hasBeenModified() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->modified);
-
-		return $this->modified;
-	}
-
-	public function isForceDelete() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->forcedelete);
-
-		return $this->forcedelete;
-	}
-
-	public function setForceDelete() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->forcedelete = true;
-		$this->oldvalues = $this->values;
-		$this->values = array();
-		$this->justModified();
-	}
-
-	public function isInternal() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->internal);
-
-		return $this->internal;
-	}
-
-	public function setInternal() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->internal = true;
-	}
-
-	public function isRequired() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->getMinValueCount() > 0)
-			return true;
-		elseif ($this->ldaptype == 'must')
-			return true;
-		elseif ($this->isRDN())
-			return true;
-		else
-			return false;
-	}
-
-	public function isMay() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if (($this->ldaptype == 'may') && ! $this->isRequired())
-			return true;
-		else
-			return false;
-	}
-
-	public function setType($type) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->type = strtolower($type);
-	}
-
-	public function getType() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->type);
-
-		return $this->type;
-	}
-
-	public function setLDAPtype($type) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->ldaptype = strtolower($type);
-	}
-
-	public function getLDAPtype() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->ldaptype);
-
-		return $this->ldaptype;
-	}
-
-	public function setProperties($properties) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		foreach ($properties as $index => $value) {
-			if ($index == 'maxvalnb') {
-				$this->setMaxValueCount($value);
-				continue;
-
-			} elseif ($index == 'minvalnb') {
-				$this->setMinValueCount($value);
-				continue;
-
-			} elseif ($index == 'maxlength') {
-				$this->setMinValueCount($value);
-				continue;
-
-			} elseif ($index == 'hidden') {
-				$this->visible = $value;
-				continue;
-
-			} elseif (in_array($index,array('cols','rows'))) {
-				# @todo To be implemented
-				continue;
-			}
-
-			if (isset($this->$index))
-				$this->$index = $value;
-			else {
-				debug_dump($this);
-				debug_dump_backtrace(sprintf('Unknown property (%s) with value (%s) for (%s)',$index,$value,$this->getName()),1);
-			}
-		}
-	}
-
-	public function setRequired() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if ($this->getMinValueCount() <= 0)
-			$this->setMinValueCount(1);
-	}
-
-	public function setOptional() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->setMinValueCount(0);
-	}
-
-	public function isReadOnly() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->readonly);
-
-		return $this->readonly;
-	}
-
-	public function setReadOnly() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->readonly = true;
-	}
-
-	public function isMultiple() {
-		return false;
-	}
-
-	public function isVisible() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		return $this->visible && (! $this->forcehide);
-	}
-
-	public function hide() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->visible = false;
-	}
-
-	public function show() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->visible = true;
-	}
-
-	public function haveFriendlyName() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		return $_SESSION[APPCONFIG]->haveFriendlyName($this);
-	}
-
-	public function getFriendlyName() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->display);
-
-		if ($this->display)
-			return $this->display;
-		else
-			return $_SESSION[APPCONFIG]->getFriendlyName($this);
-	}
-
-	public function setDescription($description) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->description = $description;
-	}
-
-	public function getDescription() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->description);
-
-		return $this->description;
-	}
-
-	public function setIcon($icon) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->icon = $icon;
-	}
-
-	public function getIcon() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->icon);
-
-		return $this->icon ? sprintf('%s/%s',IMGDIR,$this->icon) : '';
-	}
-
-	public function getHint() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->hint);
-
-		return $this->hint;
-	}
-
-	public function setHint($hint) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->hint = $hint;
-	}
-
-	public function getMaxLength() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->maxlength);
-
-		return $this->maxlength;
-	}
-
-	public function setMaxLength($maxlength) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->maxlength = $maxlength;
-	}
-
-	public function getSize() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->size);
-
-		return $this->size;
-	}
-
-	public function setSize($size) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->size = $size;
-	}
-
-	public function getSpacer() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->spacer);
-
-		return $this->spacer;
-	}
-
-	public function getPage() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->page);
-
-		return $this->page;
-	}
-	public function setPage($page) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->page = $page;
-	}
-
-	public function getOnChange() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->onchange);
-
-		return $this->onchange;
-	}
-
-	public function getHelper() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->helper);
-
-		return $this->helper;
-	}
-
-	public function getHelperValue() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->helpervalue);
-
-		return $this->helpervalue;
-	}
-
-	public function getVerify() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->verify);
-
-		return $this->verify;
-	}
-
-	public function setRDN($rdn) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->rdn = $rdn;
-	}
-
-	/**
-	 * Return if this attribute is an RDN attribute
-	 *
-	 * @return boolean
-	 */
-	public function isRDN() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->rdn);
-
-		return $this->rdn;
-	}
-
-	/**
-	 * Capture all the LDAP details we are interested in
-	 *
-	 * @param sattr Schema Attribute
-	 */
-	private function setLDAPdetails($sattr) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		# By default, set this as a MAY attribute, later processing should make it a MUST attribute if it is.
-		if (! $this->ldaptype)
-			$this->ldaptype = 'may';
-
-		# Store our Aliases
-		foreach ($sattr->getAliases() as $alias)
-			array_push($this->aliases,strtolower($alias));
-
-		if ($sattr->getIsSingleValue())
-			$this->setMaxValueCount(1);
-	}
-
-	/**
-	 * Return a list of aliases for this Attribute (as defined by the schema)
-	 * This list will be lowercase.
-	 */
-	public function getAliases() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->aliases);
-
-		return $this->aliases;
-	}
-
-	public function getAutoValue() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->autovalue);
-
-		return $this->autovalue;
-	}
-
-	public function getPostValue() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->postvalue);
-
-		return $this->postvalue;
-	}
-
-	public function setPostValue($postvalue) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		$this->postvalue = $postvalue;
-	}
-
-	public function setXML($values) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		# Mostly all the time, this should be an array
-		if (is_array($values))
-			foreach ($values as $index => $value)
-				switch ($index) {
-					# Helpers should be accompanied with a <post> attribute.
-					case 'helper':
-						if (! isset($values['post']) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
-							system_message(array(
-								'title'=>sprintf('%s [<i>%s</i>]',_('Missing [post] setting in XML file'),$index),
-								'body'=>_('[helper] needs an accompanying [post] action.'),
-								'type'=>'warn'));
-
-						if (isset($value['value']) && ! is_array($value['value']) && preg_match('/^=php\.(\w+)\((.*)\)$/',$value['value'],$matches)) {
-							$this->helpervalue['function'] = $matches[1];
-							$this->helpervalue['args'] = $matches[2];
-
-							unset ($value['value']);
-						}
-
-						foreach ($value as $i => $detail) {
-							if (! in_array($i,array('default','display','id','value'))) {
-								if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
-									system_message(array(
-										'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$i),
-										'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting for helper will be ignored.'),$detail),
-										'type'=>'warn'));
-
-								unset($value[$i]);
-							}
-						}
-
-						$this->$index = $value;
-
-						break;
-
-					case 'hidden': $value ? $this->visible = false : $this->visible = true;
-						break;
-
-					case 'spacer': $value ? $this->$index = true : $this->$index = false;
-						break;
-
-					# Essentially, we ignore type, it is used to select an Attribute type in the Factory. But we'll generated a warning if there is an unknown type.
-					case 'type':
-						if (! in_array($value,array('password','multiselect','select','textarea')) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
-							system_message(array(
-								'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
-								'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting will be ignored.'),$value),
-								'type'=>'warn'));
-
-						break;
-
-					case 'post':
-						if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) {
-							$this->postvalue['function'] = $matches[1];
-							$this->postvalue['args'] = $matches[2];
-
-						} else
-							if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
-								system_message(array(
-									'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
-									'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting will be ignored.'),$value),
-									'type'=>'warn'));
-
-					case 'value':
-						if (is_array($value))
-							foreach ($value as $x => $y) {
-								if (! $this->haveMoreValues()) {
-									system_message(array(
-									'title'=>_('Automatically removed attribute values from template'),
-										'body'=>sprintf('%s <small>[%s]</small>',_('Template defines more values than can be accepted by attribute.'),$this->getName(true)),
-										'type'=>'warn'));
-
-									$this->clearValue();
-
-									break;
-
-								} else
-									$this->addValue($x,$y);
-							}
-
-						else
-							# Check to see if the value is auto generated.
-							if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) {
-								$this->autovalue['function'] = $matches[1];
-								$this->autovalue['args'] = $matches[2];
-
-								# We'll add a hint too
-								if (! $this->hint)
-									$this->hint = _('Automatically determined');
-
-							} else
-								$this->addValue($value);
-
-						break;
-
-					# Queries
-					case 'ordersort':
-
-					# Creation/Editing Templates
-					case 'cols':
-					case 'default':
-					case 'display':
-					case 'hint':
-					case 'icon':
-					case 'maxlength':
-					case 'onchange':
-					case 'order':
-					case 'page':
-					case 'readonly':
-					case 'rows':
-					case 'size':
-					case 'values':
-					case 'verify': $this->$index = $value;
-						break;
-
-					case 'max':
-						if ($this->getMaxValueCount() == -1)
-							$this->setMaxValueCount($value);
-
-					default:
-						if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
-							system_message(array(
-								'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
-								'body'=>sprintf('%s <small>[%s]</small>',_('Unknown attribute setting will be ignored.'),serialize($value)),
-								'type'=>'warn'));
-				}
-
-		elseif (is_string($values) && (strlen($values) > 0))
-			$this->values = array($values);
-	}
-
-	/**
-	 * Display the values removed in an attribute.
-	 */
-	public function getRemovedValues() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		return array_diff($this->getOldValues(),$this->getValues());
-	}
-
-	/**
-	 * Display the values removed in an attribute.
-	 */
-	public function getAddedValues() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		return array_diff($this->getValues(),$this->getOldValues());
-	}
-
-	/**
-	 * Prunes off anything after the ";" in an attr name. This is useful for
-	 * attributes that may have ";binary" appended to their names. With
-	 * real_attr_name(), you can more easily fetch these attributes' schema
-	 * with their "real" attribute name.
-	 *
-	 * @param string $attr_name The name of the attribute to examine.
-	 * @return string
-	 */
-	private function real_attr_name() {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
-
-		return preg_replace('/;.*$/U','',$this->name);
-	}
-
-	/**
-	 * Does this attribute need supporting JS
-	 */
-	public function needJS($type=null) {
-		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
-			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
-
-		if (is_null($type)) {
-			foreach (array('focus','blur','validate') as $type)
-				if ($this->needJS($type))
-					return true;
-
-			return false;
-
-		} elseif ($type == 'focus') {
-			# We dont have any focus javascript routines.
-			return false;
-
-		} elseif ($type == 'blur') {
-			if ($this->onchange || $this->isRequired())
-				return true;
-			else
-				return false;
-
-		} elseif ($type == 'validate') {
-			if ($this->isRequired())
-				return true;
-			else
-				return false;
-
-		} else
-			debug_dump_backtrace(sprintf('Unknown JS request %s',$type),1);
-	}
-}
-?>
diff --git a/lib/AttributeFactory.php b/lib/AttributeFactory.php
index 82cf562..96bb70b 100644
--- a/lib/AttributeFactory.php
+++ b/lib/AttributeFactory.php
@@ -133,7 +133,7 @@ class AttributeFactory {
 			return $this->newGidAttribute($name,$values,$server_id,$source);
 
 		} else {
-			return new Attribute($name,$values,$server_id,$source);
+			return new PLAAttribute($name,$values,$server_id,$source);
 		}
 	}
 
diff --git a/lib/BinaryAttribute.php b/lib/BinaryAttribute.php
index 6b5053b..35fe5d2 100644
--- a/lib/BinaryAttribute.php
+++ b/lib/BinaryAttribute.php
@@ -12,7 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class BinaryAttribute extends Attribute {
+class BinaryAttribute extends PLAAttribute {
 	protected $filepaths;
 	protected $filenames;
 
diff --git a/lib/DateAttribute.php b/lib/DateAttribute.php
index e1a687f..df0b6e8 100644
--- a/lib/DateAttribute.php
+++ b/lib/DateAttribute.php
@@ -12,6 +12,6 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class DateAttribute extends Attribute {
+class DateAttribute extends PLAAttribute {
 }
 ?>
diff --git a/lib/DnAttribute.php b/lib/DnAttribute.php
index 1f5c02f..692ec65 100644
--- a/lib/DnAttribute.php
+++ b/lib/DnAttribute.php
@@ -12,6 +12,6 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class DnAttribute extends Attribute {
+class DnAttribute extends PLAAttribute {
 }
 ?>
diff --git a/lib/GidAttribute.php b/lib/GidAttribute.php
index 7442a07..4ea0d12 100644
--- a/lib/GidAttribute.php
+++ b/lib/GidAttribute.php
@@ -12,6 +12,6 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class GidAttribute extends Attribute {
+class GidAttribute extends PLAAttribute {
 }
 ?>
diff --git a/lib/MultiLineAttribute.php b/lib/MultiLineAttribute.php
index b6d0eb5..2da4bb9 100644
--- a/lib/MultiLineAttribute.php
+++ b/lib/MultiLineAttribute.php
@@ -12,7 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class MultiLineAttribute extends Attribute {
+class MultiLineAttribute extends PLAAttribute {
 	protected $rows = 0;
 	protected $cols = 0;
 
diff --git a/lib/ObjectClassAttribute.php b/lib/ObjectClassAttribute.php
index 939094d..7807098 100644
--- a/lib/ObjectClassAttribute.php
+++ b/lib/ObjectClassAttribute.php
@@ -12,6 +12,6 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class ObjectClassAttribute extends Attribute {
+class ObjectClassAttribute extends PLAAttribute {
 }
 ?>
diff --git a/lib/PLAAttribute.php b/lib/PLAAttribute.php
new file mode 100644
index 0000000..a2f0091
--- /dev/null
+++ b/lib/PLAAttribute.php
@@ -0,0 +1,917 @@
+<?php
+/**
+ * Classes and functions for the template engine.
+ *
+ * @author The phpLDAPadmin development team
+ * @package phpLDAPadmin
+ */
+
+/**
+ * Represents an attribute of a template.
+ *
+ * @package phpLDAPadmin
+ * @subpackage Templates
+ */
+class PLAAttribute {
+	# Attribute Name
+	public $name;
+	# Source of this attribute definition
+	protected $source;
+
+	# Current and Old Values
+	protected $oldvalues = array();
+	protected $values = array();
+
+	# MIN/MAX number of values
+	protected $min_value_count = -1;
+	protected $max_value_count = -1;
+
+	# Is the attribute internal
+	protected $internal = false;
+	# Has the attribute been modified
+	protected $modified = false;
+	# Is the attribute being deleted because of an object class removal
+	protected $forcedelete = false;
+	# Is the attribute visible
+	protected $visible = false;
+	protected $forcehide = false;
+	# Is the attribute modifiable
+	protected $readonly = false;
+	# LDAP attribute type MUST/MAY
+	protected $ldaptype = null;
+	# Attribute property type (eg password, select, multiselect)
+	protected $type = '';
+	# Attribute value to keep unique
+	protected $unique = false;
+
+	# Display parameters
+	protected $display = '';
+	protected $icon = '';
+	protected $hint = '';
+	# Helper details
+	protected $helper = array();
+	protected $helpervalue = array();
+	# Onchange details
+	protected $onchange = array();
+	# Show spacer after this attribute is rendered
+	protected $spacer = false;
+	protected $verify = false;
+
+	# Component size
+	protected $size = 0;
+	# Value max length
+	protected $maxlength = 0;
+	# Text Area sizings
+	protected $cols = 0;
+	protected $rows = 0;
+
+	# Public for sorting
+	public $page = 1;
+	public $order = 255;
+	public $ordersort = 255;
+	public $rdn = false;
+
+	# Schema Aliases for this attribute (stored in lowercase)
+	protected $aliases = array();
+
+	# Configuration for automatically generated values
+	protected $autovalue = array();
+	protected $postvalue = array();
+
+	public function __construct($name,$values,$server_id,$source=null) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$server = $_SESSION[APPCONFIG]->getServer($server_id);
+
+		$sattr = $server->getSchemaAttribute($name);
+		if ($sattr) {
+			$this->name = $sattr->getName(false);
+			$this->setLDAPdetails($sattr);
+
+		} else
+			$this->name = $name;
+
+		$this->source = $source;
+
+		# XML attributes are shown by default
+		switch ($source) {
+			case 'XML': $this->show();
+				$this->setXML($values);
+
+				break;
+
+			default:
+				if (! isset($values['values']))
+					debug_dump_backtrace('no index "values"',1);
+
+				$this->initValue($values['values']);
+		}
+
+		# Should this attribute be hidden
+		if ($server->isAttrHidden($this->name))
+			$this->forcehide = true;
+
+		# Should this attribute value be read only
+		if ($server->isAttrReadOnly($this->name))
+			$this->readonly = true;
+
+		# Should this attribute value be unique
+		if ($server->isAttrUnique($this->name))
+			$this->unique = true;
+	}
+
+	/**
+	 * Return the name of the attribute.
+	 *
+	 * @param boolean $lower - Return the attribute in normal or lower case (default lower)
+	 * @param boolean $real - Return the real attribute name (with ;binary, or just the name)
+	 * @return string Attribute name
+	 */
+	public function getName($lower=true,$real=false) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
+
+		if ($real)
+			return $lower ? strtolower($this->name) : $this->name;
+		else
+			return $lower ? strtolower($this->real_attr_name()) : $this->real_attr_name();
+	}
+
+	public function getValues() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->values);
+
+		return $this->values;
+	}
+
+	public function getOldValues() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->oldvalues);
+
+		return $this->oldvalues;
+	}
+
+	public function getValueCount() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->values);
+
+		return count($this->values);
+	}
+
+	public function getSource() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->source);
+
+		return $this->source;
+	}
+
+	/**
+	 * Autovalue is called after the attribute is initialised, and thus the values from the ldap server will be set.
+	 */
+	public function autoValue($new_val) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->values)
+			return;
+
+		$this->values = $new_val;
+	}
+
+	public function initValue($new_val) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->values || $this->oldvalues) {
+			debug_dump(array('new_val'=>$new_val,'this'=>$this));
+			debug_dump_backtrace('new and/or old values are set',1);
+		}
+
+		$this->values = $new_val;
+	}
+
+	public function clearValue() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->values = array();
+	}
+
+	public function setOldValue($val) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->oldvalues = $val;
+	}
+
+	public function setValue($new_val) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->values) {
+			if ($this->values == $new_val)
+				return;
+
+			if ($this->oldvalues) {
+				debug_dump($this);
+				debug_dump_backtrace('old values are set',1);
+			} else
+				$this->oldvalues = $this->values;
+		}
+
+		if ($new_val == $this->values)
+			return;
+
+		$this->values = $new_val;
+		$this->justModified();
+	}
+
+	public function addValue($new_val,$i=-1) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($i < 0)
+			$i = $this->getValueCount();
+
+		$old_val = $this->getValue($i);
+		if (is_null($old_val) || ($old_val != $new_val))
+			$this->justModified();
+
+		$this->values[$i] = $new_val;
+	}
+
+	public function delValue($i=-1) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($i < 0)
+			$this->setValue(array());
+
+		if (! $this->hasBeenModified())
+			$this->oldvalues = $this->values;
+
+		if (isset($this->values[$i])) {
+			unset($this->values[$i]);
+			$this->values = array_values($this->values);
+			$this->justModified();
+		}
+	}
+
+	public function getValue($i, $default=null) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if (isset($this->values[$i]))
+			return $this->values[$i];
+		else
+			return $default;
+	}
+
+	public function getOldValue($i) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if (isset($this->oldvalues[$i]))
+			return $this->oldvalues[$i];
+		else
+			return null;
+	}
+
+	public function getMinValueCount() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->min_value_count);
+
+		return $this->min_value_count;
+	}
+
+	public function setMinValueCount($min) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->min_value_count = $min;
+	}
+
+	public function getMaxValueCount() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->max_value_count);
+
+		return $this->max_value_count;
+	}
+
+	public function setMaxValueCount($max) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->max_value_count = $max;
+	}
+
+	public function haveMoreValues() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->getMaxValueCount() < 0 || ($this->getValueCount() < $this->getMaxValueCount()))
+			return true;
+		else
+			return false;
+	}
+
+	public function justModified() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->modified = true;
+	}
+
+	public function hasBeenModified() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->modified);
+
+		return $this->modified;
+	}
+
+	public function isForceDelete() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->forcedelete);
+
+		return $this->forcedelete;
+	}
+
+	public function setForceDelete() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->forcedelete = true;
+		$this->oldvalues = $this->values;
+		$this->values = array();
+		$this->justModified();
+	}
+
+	public function isInternal() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->internal);
+
+		return $this->internal;
+	}
+
+	public function setInternal() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->internal = true;
+	}
+
+	public function isRequired() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->getMinValueCount() > 0)
+			return true;
+		elseif ($this->ldaptype == 'must')
+			return true;
+		elseif ($this->isRDN())
+			return true;
+		else
+			return false;
+	}
+
+	public function isMay() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if (($this->ldaptype == 'may') && ! $this->isRequired())
+			return true;
+		else
+			return false;
+	}
+
+	public function setType($type) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->type = strtolower($type);
+	}
+
+	public function getType() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->type);
+
+		return $this->type;
+	}
+
+	public function setLDAPtype($type) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->ldaptype = strtolower($type);
+	}
+
+	public function getLDAPtype() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->ldaptype);
+
+		return $this->ldaptype;
+	}
+
+	public function setProperties($properties) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		foreach ($properties as $index => $value) {
+			if ($index == 'maxvalnb') {
+				$this->setMaxValueCount($value);
+				continue;
+
+			} elseif ($index == 'minvalnb') {
+				$this->setMinValueCount($value);
+				continue;
+
+			} elseif ($index == 'maxlength') {
+				$this->setMinValueCount($value);
+				continue;
+
+			} elseif ($index == 'hidden') {
+				$this->visible = $value;
+				continue;
+
+			} elseif (in_array($index,array('cols','rows'))) {
+				# @todo To be implemented
+				continue;
+			}
+
+			if (isset($this->$index))
+				$this->$index = $value;
+			else {
+				debug_dump($this);
+				debug_dump_backtrace(sprintf('Unknown property (%s) with value (%s) for (%s)',$index,$value,$this->getName()),1);
+			}
+		}
+	}
+
+	public function setRequired() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if ($this->getMinValueCount() <= 0)
+			$this->setMinValueCount(1);
+	}
+
+	public function setOptional() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->setMinValueCount(0);
+	}
+
+	public function isReadOnly() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->readonly);
+
+		return $this->readonly;
+	}
+
+	public function setReadOnly() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->readonly = true;
+	}
+
+	public function isMultiple() {
+		return false;
+	}
+
+	public function isVisible() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		return $this->visible && (! $this->forcehide);
+	}
+
+	public function hide() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->visible = false;
+	}
+
+	public function show() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->visible = true;
+	}
+
+	public function haveFriendlyName() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		return $_SESSION[APPCONFIG]->haveFriendlyName($this);
+	}
+
+	public function getFriendlyName() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->display);
+
+		if ($this->display)
+			return $this->display;
+		else
+			return $_SESSION[APPCONFIG]->getFriendlyName($this);
+	}
+
+	public function setDescription($description) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->description = $description;
+	}
+
+	public function getDescription() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->description);
+
+		return $this->description;
+	}
+
+	public function setIcon($icon) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->icon = $icon;
+	}
+
+	public function getIcon() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->icon);
+
+		return $this->icon ? sprintf('%s/%s',IMGDIR,$this->icon) : '';
+	}
+
+	public function getHint() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->hint);
+
+		return $this->hint;
+	}
+
+	public function setHint($hint) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->hint = $hint;
+	}
+
+	public function getMaxLength() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->maxlength);
+
+		return $this->maxlength;
+	}
+
+	public function setMaxLength($maxlength) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->maxlength = $maxlength;
+	}
+
+	public function getSize() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->size);
+
+		return $this->size;
+	}
+
+	public function setSize($size) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->size = $size;
+	}
+
+	public function getSpacer() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->spacer);
+
+		return $this->spacer;
+	}
+
+	public function getPage() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->page);
+
+		return $this->page;
+	}
+	public function setPage($page) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->page = $page;
+	}
+
+	public function getOnChange() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->onchange);
+
+		return $this->onchange;
+	}
+
+	public function getHelper() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->helper);
+
+		return $this->helper;
+	}
+
+	public function getHelperValue() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->helpervalue);
+
+		return $this->helpervalue;
+	}
+
+	public function getVerify() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->verify);
+
+		return $this->verify;
+	}
+
+	public function setRDN($rdn) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->rdn = $rdn;
+	}
+
+	/**
+	 * Return if this attribute is an RDN attribute
+	 *
+	 * @return boolean
+	 */
+	public function isRDN() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->rdn);
+
+		return $this->rdn;
+	}
+
+	/**
+	 * Capture all the LDAP details we are interested in
+	 *
+	 * @param sattr Schema Attribute
+	 */
+	private function setLDAPdetails($sattr) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		# By default, set this as a MAY attribute, later processing should make it a MUST attribute if it is.
+		if (! $this->ldaptype)
+			$this->ldaptype = 'may';
+
+		# Store our Aliases
+		foreach ($sattr->getAliases() as $alias)
+			array_push($this->aliases,strtolower($alias));
+
+		if ($sattr->getIsSingleValue())
+			$this->setMaxValueCount(1);
+	}
+
+	/**
+	 * Return a list of aliases for this Attribute (as defined by the schema)
+	 * This list will be lowercase.
+	 */
+	public function getAliases() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->aliases);
+
+		return $this->aliases;
+	}
+
+	public function getAutoValue() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->autovalue);
+
+		return $this->autovalue;
+	}
+
+	public function getPostValue() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->postvalue);
+
+		return $this->postvalue;
+	}
+
+	public function setPostValue($postvalue) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		$this->postvalue = $postvalue;
+	}
+
+	public function setXML($values) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		# Mostly all the time, this should be an array
+		if (is_array($values))
+			foreach ($values as $index => $value)
+				switch ($index) {
+					# Helpers should be accompanied with a <post> attribute.
+					case 'helper':
+						if (! isset($values['post']) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+							system_message(array(
+								'title'=>sprintf('%s [<i>%s</i>]',_('Missing [post] setting in XML file'),$index),
+								'body'=>_('[helper] needs an accompanying [post] action.'),
+								'type'=>'warn'));
+
+						if (isset($value['value']) && ! is_array($value['value']) && preg_match('/^=php\.(\w+)\((.*)\)$/',$value['value'],$matches)) {
+							$this->helpervalue['function'] = $matches[1];
+							$this->helpervalue['args'] = $matches[2];
+
+							unset ($value['value']);
+						}
+
+						foreach ($value as $i => $detail) {
+							if (! in_array($i,array('default','display','id','value'))) {
+								if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+									system_message(array(
+										'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$i),
+										'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting for helper will be ignored.'),$detail),
+										'type'=>'warn'));
+
+								unset($value[$i]);
+							}
+						}
+
+						$this->$index = $value;
+
+						break;
+
+					case 'hidden': $value ? $this->visible = false : $this->visible = true;
+						break;
+
+					case 'spacer': $value ? $this->$index = true : $this->$index = false;
+						break;
+
+					# Essentially, we ignore type, it is used to select an Attribute type in the Factory. But we'll generated a warning if there is an unknown type.
+					case 'type':
+						if (! in_array($value,array('password','multiselect','select','textarea')) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+							system_message(array(
+								'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
+								'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting will be ignored.'),$value),
+								'type'=>'warn'));
+
+						break;
+
+					case 'post':
+						if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) {
+							$this->postvalue['function'] = $matches[1];
+							$this->postvalue['args'] = $matches[2];
+
+						} else
+							if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+								system_message(array(
+									'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
+									'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting will be ignored.'),$value),
+									'type'=>'warn'));
+
+					case 'value':
+						if (is_array($value))
+							foreach ($value as $x => $y) {
+								if (! $this->haveMoreValues()) {
+									system_message(array(
+									'title'=>_('Automatically removed attribute values from template'),
+										'body'=>sprintf('%s <small>[%s]</small>',_('Template defines more values than can be accepted by attribute.'),$this->getName(true)),
+										'type'=>'warn'));
+
+									$this->clearValue();
+
+									break;
+
+								} else
+									$this->addValue($x,$y);
+							}
+
+						else
+							# Check to see if the value is auto generated.
+							if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) {
+								$this->autovalue['function'] = $matches[1];
+								$this->autovalue['args'] = $matches[2];
+
+								# We'll add a hint too
+								if (! $this->hint)
+									$this->hint = _('Automatically determined');
+
+							} else
+								$this->addValue($value);
+
+						break;
+
+					# Queries
+					case 'ordersort':
+
+					# Creation/Editing Templates
+					case 'cols':
+					case 'default':
+					case 'display':
+					case 'hint':
+					case 'icon':
+					case 'maxlength':
+					case 'onchange':
+					case 'order':
+					case 'page':
+					case 'readonly':
+					case 'rows':
+					case 'size':
+					case 'values':
+					case 'verify': $this->$index = $value;
+						break;
+
+					case 'max':
+						if ($this->getMaxValueCount() == -1)
+							$this->setMaxValueCount($value);
+
+					default:
+						if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+							system_message(array(
+								'title'=>sprintf('%s [<i>%s</i>]',_('Unknown XML setting'),$index),
+								'body'=>sprintf('%s <small>[%s]</small>',_('Unknown attribute setting will be ignored.'),serialize($value)),
+								'type'=>'warn'));
+				}
+
+		elseif (is_string($values) && (strlen($values) > 0))
+			$this->values = array($values);
+	}
+
+	/**
+	 * Display the values removed in an attribute.
+	 */
+	public function getRemovedValues() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		return array_diff($this->getOldValues(),$this->getValues());
+	}
+
+	/**
+	 * Display the values removed in an attribute.
+	 */
+	public function getAddedValues() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		return array_diff($this->getValues(),$this->getOldValues());
+	}
+
+	/**
+	 * Prunes off anything after the ";" in an attr name. This is useful for
+	 * attributes that may have ";binary" appended to their names. With
+	 * real_attr_name(), you can more easily fetch these attributes' schema
+	 * with their "real" attribute name.
+	 *
+	 * @param string $attr_name The name of the attribute to examine.
+	 * @return string
+	 */
+	private function real_attr_name() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
+
+		return preg_replace('/;.*$/U','',$this->name);
+	}
+
+	/**
+	 * Does this attribute need supporting JS
+	 */
+	public function needJS($type=null) {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+
+		if (is_null($type)) {
+			foreach (array('focus','blur','validate') as $type)
+				if ($this->needJS($type))
+					return true;
+
+			return false;
+
+		} elseif ($type == 'focus') {
+			# We dont have any focus javascript routines.
+			return false;
+
+		} elseif ($type == 'blur') {
+			if ($this->onchange || $this->isRequired())
+				return true;
+			else
+				return false;
+
+		} elseif ($type == 'validate') {
+			if ($this->isRequired())
+				return true;
+			else
+				return false;
+
+		} else
+			debug_dump_backtrace(sprintf('Unknown JS request %s',$type),1);
+	}
+}
+?>
diff --git a/lib/PasswordAttribute.php b/lib/PasswordAttribute.php
index 2667197..5971576 100644
--- a/lib/PasswordAttribute.php
+++ b/lib/PasswordAttribute.php
@@ -12,6 +12,6 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class PasswordAttribute extends Attribute {
+class PasswordAttribute extends PLAAttribute {
 }
 ?>
diff --git a/lib/SelectionAttribute.php b/lib/SelectionAttribute.php
index 5f1c8bb..dfb13c7 100644
--- a/lib/SelectionAttribute.php
+++ b/lib/SelectionAttribute.php
@@ -12,7 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class SelectionAttribute extends Attribute {
+class SelectionAttribute extends PLAAttribute {
 	protected $selection = array();
 	protected $multiple;
 	protected $default;
diff --git a/lib/ShadowAttribute.php b/lib/ShadowAttribute.php
index eeb7cd1..0dcf915 100644
--- a/lib/ShadowAttribute.php
+++ b/lib/ShadowAttribute.php
@@ -12,7 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Templates
  */
-class ShadowAttribute extends Attribute {
+class ShadowAttribute extends PLAAttribute {
 	public $shadow_before_today_attrs = array('shadowLastChange','shadowMin');
 	public $shadow_after_today_attrs = array('shadowMax','shadowExpire','shadowWarning','shadowInactive');
 }
diff --git a/lib/Visitor.php b/lib/Visitor.php
index fca5099..b840e7b 100644
--- a/lib/Visitor.php
+++ b/lib/Visitor.php
@@ -22,6 +22,15 @@ abstract class Visitor {
 	protected $server_id;
 
 	public function __call($method,$args) {
+		# This mapping array allows to map effective class names to
+		# function name suffixes.
+		# It has been introduced when class Attribute has been renamed
+		# to PLAAttribute to avoid a name clash with the built-in
+		# class of PHP 8.
+		# Entering a class name mapping here allows to rename the
+		# class without having to rename the methods too.
+		static $classmap = array('PLAAttribute' => 'Attribute');
+
 		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 			debug_log('Entered (%%)',129,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
@@ -33,19 +42,14 @@ abstract class Visitor {
 		$fnct = array_shift($args);
 
 		$object = $args[0];
-		$class = get_class($object);
-
-		$call = "$method$fnct$class";
-
-		array_push($methods,$call);
 
-		while ($class && ! method_exists($this,$call)) {
+		for ($class = get_class($object); $class; $class = get_parent_class($class)) {
+			$call = isset($classmap[$class])? "$method$fnct$classmap[$class]": "$method$fnct$class";
+			array_push($methods,$call);
+			if (method_exists($this,$call))
+				break;
 			if (defined('DEBUGTMP') && DEBUGTMP)
 				printf('<font size=-2><i>Class (%s): Method doesnt exist (%s,%s)</i></font><br />',$class,get_class($this),$call);
-
-			$class = get_parent_class($class);
-			$call = "$method$fnct$class";
-			array_push($methods,$call);
 		}
 
 		if (defined('DEBUGTMP') && DEBUGTMP)
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 16:00:11 +0100
Subject: Fix PHP 8.1 deprecated code

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/9488fe2ed7841bffc322c6c9afeb9fc3e2bd0a42
---
 htdocs/export_form.php      |  2 +-
 htdocs/login.php            |  3 +--
 htdocs/password_checker.php |  4 ++--
 htdocs/schema.php           |  6 +++---
 lib/Attribute.php           |  4 ++--
 lib/PageRender.php          | 16 ++++++++--------
 lib/Query.php               |  2 +-
 lib/Template.php            |  9 ++++++---
 lib/TemplateRender.php      |  2 +-
 lib/ds_ldap.php             |  6 +++---
 lib/functions.php           |  9 +++++++++
 lib/schema_functions.php    | 14 +++++++-------
 lib/xmlTemplates.php        |  4 ++--
 13 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/htdocs/export_form.php b/htdocs/export_form.php
index d0a82b0..64d856f 100755
--- a/htdocs/export_form.php
+++ b/htdocs/export_form.php
@@ -13,7 +13,7 @@ require './common.php';
 require LIBDIR.'export_functions.php';
 
 $request = array();
-$request['dn'] = get_request('dn','GET');
+$request['dn'] = get_request('dn','GET',false,'');
 $request['format'] = get_request('format','GET',false,get_line_end_format());
 $request['scope'] = get_request('scope','GET',false,'base');
 $request['exporter_id'] = get_request('exporter_id','GET',false,'LDIF');
diff --git a/htdocs/login.php b/htdocs/login.php
index 06b7fa1..988dbcf 100644
--- a/htdocs/login.php
+++ b/htdocs/login.php
@@ -19,8 +19,7 @@ if ($_SESSION[APPCONFIG]->getValue('session', 'reCAPTCHA-enable')) {
 if ($pass) {
     $user             = array();
     $user['login']    = get_request('login');
-    $user['password'] = get_request('login_pass');
-    $user['password'] = html_entity_decode($user['password'], ENT_QUOTES);
+    $user['password'] = get_request('login_pass', 'POST', false, '');
 
     if ($user['login'] && !strlen($user['password'])) {
         system_message(array(
diff --git a/htdocs/password_checker.php b/htdocs/password_checker.php
index c616e2e..ce0cf0d 100644
--- a/htdocs/password_checker.php
+++ b/htdocs/password_checker.php
@@ -15,8 +15,8 @@ $www['page'] = new page();
 
 $request = array();
 $request['componentid'] = get_request('componentid','REQUEST');
-$request['hash'] = get_request('hash','REQUEST');
-$request['password'] = get_request('check_password','REQUEST');
+$request['hash'] = get_request('hash','REQUEST',false,'');
+$request['password'] = get_request('check_password','REQUEST',false,'');
 $request['action'] = get_request('action','REQUEST');
 $request['attribute'] = get_request('attr','REQUEST');
 
diff --git a/htdocs/schema.php b/htdocs/schema.php
index aa4a749..e4ef14e 100644
--- a/htdocs/schema.php
+++ b/htdocs/schema.php
@@ -150,7 +150,7 @@ switch($entry['view']) {
 
 		foreach ($sattrs as $attr) {
 			if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$attr->getName())) {
-				if ((! is_null($entry['value']) && $entry['value']==$attr->getName()) || ! trim($entry['value']))
+				if (!is_string($entry['value']) || $entry['value']==$attr->getName() || !trim($entry['value']))
 					$entry['viewed'] = true;
 
 				if (isAjaxEnabled() && $entry['value'])
@@ -380,7 +380,7 @@ switch($entry['view']) {
 			$desc = $rule->getName(false);
 
 			if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$rule->getName())) {
-				if ((! is_null($entry['value']) && $entry['value']==$rule->getName()) || ! trim($entry['value']))
+				if (!is_string($entry['value']) || $entry['value']==$rule->getName() || !trim($entry['value']))
 					$entry['viewed'] = true;
 
 				if (null != $rule->getDescription())
@@ -468,7 +468,7 @@ switch($entry['view']) {
 
 		foreach ($socs as $name => $oclass) {
 			if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$oclass->getName())) {
-				if ((! is_null($entry['value']) && $entry['value']==$oclass->getName()) || ! trim($entry['value']))
+				if (!is_string($entry['value']) || $entry['value']==$oclass->getName() || !trim($entry['value']))
 					$entry['viewed'] = true;
 
 				if (isAjaxEnabled() && $entry['value'])
diff --git a/lib/Attribute.php b/lib/Attribute.php
index 9c4ef98..3d040db 100644
--- a/lib/Attribute.php
+++ b/lib/Attribute.php
@@ -258,14 +258,14 @@ class Attribute {
 		}
 	}
 
-	public function getValue($i) {
+	public function getValue($i, $default=null) {
 		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
 		if (isset($this->values[$i]))
 			return $this->values[$i];
 		else
-			return null;
+			return $default;
 	}
 
 	public function getOldValue($i) {
diff --git a/lib/PageRender.php b/lib/PageRender.php
index f3c4169..479f9ec 100644
--- a/lib/PageRender.php
+++ b/lib/PageRender.php
@@ -538,7 +538,7 @@ class PageRender extends Visitor {
 	final protected function drawHiddenValueAttribute($attribute,$i) {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		printf('<input type="hidden" name="new_values[%s][%s]" id="new_values_%s_%s" value="%s" />',
 			htmlspecialchars($attribute->getName()),$i,htmlspecialchars($attribute->getName()),$i,
@@ -607,7 +607,7 @@ class PageRender extends Visitor {
 	protected function drawFormReadOnlyValueAttribute($attribute,$i) {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		printf('<input type="text" class="roval" name="new_values[%s][%s]" id="new_values_%s_%s" value="%s" readonly="readonly" />',
 			htmlspecialchars($attribute->getName()),$i,htmlspecialchars($attribute->getName()),$i,htmlspecialchars($val));
@@ -616,7 +616,7 @@ class PageRender extends Visitor {
 	protected function drawFormReadWriteValueAttribute($attribute,$i) {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		if ($attribute->getHelper() || $attribute->getVerify())
 			echo '<table cellspacing="0" cellpadding="0" border="0"><tr><td valign="top">';
@@ -720,7 +720,7 @@ class PageRender extends Visitor {
 	protected function drawFormReadWriteValueDateAttribute($attribute,$i) {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		echo '<span style="white-space: nowrap;">';
 		printf('<input type="text" class="value" id="new_values_%s_%s" name="new_values[%s][%s]" value="%s" %s%s %s %s/>&nbsp;',
@@ -738,7 +738,7 @@ class PageRender extends Visitor {
 	protected function drawFormReadWriteValueDnAttribute($attribute,$i) {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		if ($attribute->getHelper())
 			echo '<table cellspacing="0" cellpadding="0"><tr><td valign="top">';
@@ -952,7 +952,7 @@ class PageRender extends Visitor {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
 		$server = $this->getServer();
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		if (trim($val))
 			$enc_type = get_enc_type($val);
@@ -974,7 +974,7 @@ class PageRender extends Visitor {
 		if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
 
 		$server = $this->getServer();
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		$enc_type = get_enc_type($val);
 
@@ -1102,7 +1102,7 @@ class PageRender extends Visitor {
 
 		# This is a single value attribute
 		} else {
-			$val = $attribute->getValue($i) ? $attribute->getValue($i) : $attribute->getDefault();
+			$val = $attribute->getValue($i) ? $attribute->getValue($i) : (is_null($attribute->getDefault())? '': $attribute->getDefault());
 
 			if ($attribute->getHelper())
 				echo '<table cellspacing="0" cellpadding="0"><tr><td valign="top">';
diff --git a/lib/Query.php b/lib/Query.php
index 62a3d2b..cc2a4f3 100644
--- a/lib/Query.php
+++ b/lib/Query.php
@@ -136,7 +136,7 @@ class Query extends xmlTemplate {
 			$bases = get_request('base','REQUEST',false,null);
 			$query['filter'] = get_request('filter','REQUEST',false,'objectClass=*');
 			$query['scope'] = get_request('scope','REQUEST',false,'sub');
-			$attrs = get_request('display_attrs','REQUEST');
+			$attrs = get_request('display_attrs','REQUEST',false,'');
 
 			$attrs = preg_replace('/\s+/','',$attrs);
 			if ($attrs)
diff --git a/lib/Template.php b/lib/Template.php
index 4a0bcb2..2e4978f 100644
--- a/lib/Template.php
+++ b/lib/Template.php
@@ -56,7 +56,7 @@ class Template extends xmlTemplate {
 	# Template RDN attributes
 	private $rdn;
 
-	public function __construct($server_id,$name=null,$filename=null,$type=null,$id=null) {
+	public function __construct($server_id,$name='',$filename=null,$type=null,$id=null) {
 		parent::__construct($server_id,$name,$filename,$type,$id);
 
 		# If this is the default template, we might disable leafs by default.
@@ -636,10 +636,13 @@ class Template extends xmlTemplate {
 
 	public function getDNEncode($url=true) {
 		// @todo Be nice to do all this in 1 location
+		$dn = $this->getDN();
+		if (is_null($dn))
+			$dn = '';
 		if ($url)
-			return urlencode(preg_replace('/%([0-9a-fA-F]+)/',"%25\\1",$this->getDN()));
+			return urlencode(preg_replace('/%([0-9a-fA-F]+)/',"%25\\1",$dn));
 		else
-			return preg_replace('/%([0-9a-fA-F]+)/',"%25\\1",$this->getDN());
+			return preg_replace('/%([0-9a-fA-F]+)/',"%25\\1",$dn);
 	}
 
 	/**
diff --git a/lib/TemplateRender.php b/lib/TemplateRender.php
index a9f2649..b19d764 100644
--- a/lib/TemplateRender.php
+++ b/lib/TemplateRender.php
@@ -2156,7 +2156,7 @@ function fillRec(id,value) {
 		if ($attribute->isMultiple() && $i > 0)
 			return;
 
-		$val = $attribute->getValue($i);
+		$val = $attribute->getValue($i, '');
 
 		if ($attribute->isVisible()) {
 			echo '<table cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td class="icon" style="width: 25px;">';
diff --git a/lib/ds_ldap.php b/lib/ds_ldap.php
index faa8478..9537ff2 100644
--- a/lib/ds_ldap.php
+++ b/lib/ds_ldap.php
@@ -2316,7 +2316,7 @@ class ldap extends DS {
 		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 			debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
-		$type = ($sattr = $this->getSchemaAttribute($attr_name)) ? $sattr->getType() : null;
+		$type = ($sattr = $this->getSchemaAttribute($attr_name)) ? $sattr->getType() : '';
 
 		if (! strcasecmp('boolean',$type) ||
 			! strcasecmp('isCriticalSystemObject',$attr_name) ||
@@ -2381,8 +2381,8 @@ class ldap extends DS {
 
 			/* Strangely, some attributeTypes may not show up in the server
 			 * schema. This behavior has been observed in MS Active Directory.*/
-			$type = null;
-			$syntax = null;
+			$type = '';
+			$syntax = '';
 
 		} else {
 			$type = $sattr->getType();
diff --git a/lib/functions.php b/lib/functions.php
index 8e8c63a..c8e509c 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -1293,6 +1293,9 @@ function is_mail_string($str) {
 	if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 		debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
+	if (is_null($str))
+		return false;
+
 	$mail_regex = "/^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$/";
 
 	if (preg_match($mail_regex,$str))
@@ -1311,6 +1314,9 @@ function is_url_string($str) {
 	if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 		debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
+	if (is_null($str))
+		return false;
+
 	$url_regex = '/^(ftp|https?):\/\/+[\w\.\-\/\?\=\&]*\w+/';
 
 	if (preg_match($url_regex,$str))
@@ -2672,6 +2678,9 @@ function pla_explode_dn($dn,$with_attributes=0) {
 
 	global $CACHE;
 
+	if (is_null($dn))
+		$dn = '';
+
 	if (isset($CACHE['explode'][$dn][$with_attributes])) {
 		if (DEBUG_ENABLED)
 			debug_log('Return CACHED result (%s) for (%s)',1,0,__FILE__,__LINE__,__METHOD__,
diff --git a/lib/schema_functions.php b/lib/schema_functions.php
index efa0cbc..6218064 100644
--- a/lib/schema_functions.php
+++ b/lib/schema_functions.php
@@ -18,11 +18,11 @@
  */
 abstract class SchemaItem {
 	# The schema item's name.
-	protected $name = null;
+	protected $name = '';
 	# The OID of this schema item.
 	private $oid = null;
 	# The description of this schema item.
-	protected $description = null;
+	protected $description = '';
 	# Boolean value indicating whether this objectClass is obsolete
 	private $is_obsolete = false;
 
@@ -703,7 +703,7 @@ class ObjectClass_ObjectClassAttribute {
  */
 class AttributeType extends SchemaItem {
 	# The attribute from which this attribute inherits (if any)
-	private $sup_attribute = null;
+	private $sup_attribute = '';
 	# The equality rule used
 	private $equality = null;
 	# The ordering of the attributeType
@@ -711,8 +711,8 @@ class AttributeType extends SchemaItem {
 	# Boolean: supports substring matching?
 	private $sub_str = null;
 	# The full syntax string, ie 1.2.3.4{16}
-	private $syntax = null;
-	private $syntax_oid = null;
+	private $syntax = '';
+	private $syntax_oid = '';
 	# boolean: is single valued only?
 	private $is_single_value = false;
 	# boolean: is collective?
@@ -726,7 +726,7 @@ class AttributeType extends SchemaItem {
 	# The max number of characters this attribute can be
 	private $max_length = null;
 	# A string description of the syntax type (taken from the LDAPSyntaxes)
-	private $type = null;
+	private $type = '';
 	# An array of objectClasses which use this attributeType (must be set by caller)
 	private $used_in_object_classes = array();
 	# A list of object class names that require this attribute type.
@@ -1327,7 +1327,7 @@ class Syntax extends SchemaItem {
  */
 class MatchingRule extends SchemaItem {
 	# This rule's syntax OID
-	private $syntax = null;
+	private $syntax = '';
 	# An array of attribute names who use this MatchingRule
 	private $used_by_attrs = array();
 
diff --git a/lib/xmlTemplates.php b/lib/xmlTemplates.php
index f55e876..68725f8 100644
--- a/lib/xmlTemplates.php
+++ b/lib/xmlTemplates.php
@@ -230,7 +230,7 @@ abstract class xmlTemplates {
 				return clone $template;
 
 		# If we get here, the template ID didnt exist, so return a blank template, which be interpreted as the default template
-		$object = new $class['name']($this->server_id,null,null,'default');
+		$object = new $class['name']($this->server_id,'',null,'default');
 		return $object;
 	}
 
@@ -272,7 +272,7 @@ abstract class xmlTemplate {
 	# The TEMPLATE attributes as per the template definition, or the DN entry
 	protected $attributes = array();
 
-	public function __construct($server_id,$name=null,$filename=null,$type=null,$id=null) {
+	public function __construct($server_id,$name='',$filename=null,$type=null,$id=null) {
 		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 15:54:07 +0100
Subject: Fix deprecated float conversion

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/issues/193
---
 lib/createlm.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/createlm.php b/lib/createlm.php
index 3dc4bb1..fff3a61 100644
--- a/lib/createlm.php
+++ b/lib/createlm.php
@@ -284,8 +284,8 @@ private $sbox = array(array(array(14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12
 		$key2 = $this->str_to_key($key);
 	
 		for ($i = 0; $i < 64; $i++) {
-			$inb[$i] = ($in[$i/8] & (1<<(7-($i%8)))) ? 1:0;
-			$keyb[$i] = ($key2[$i/8] & (1<<(7-($i%8)))) ? 1:0;
+			$inb[$i] = ($in[intdiv($i, 8)] & (1<<(7-($i%8)))) ? 1:0;
+			$keyb[$i] = ($key2[intdiv($i, 8)] & (1<<(7-($i%8)))) ? 1:0;
 			$outb[$i] = 0;
 		}
 		$outb = $this->doHash($inb, $keyb, $forw);
@@ -294,7 +294,7 @@ private $sbox = array(array(array(14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12
 		}
 		for ($i = 0; $i < 64; $i++) {
 			if ( $outb[$i] )  {
-				$out[$i/8] |= (1<<(7-($i%8)));
+				$out[intdiv($i, 8)] |= (1<<(7-($i%8)));
 			}
 		}
 		return $out;
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 15:36:58 +0100
Subject: Fix Creation of dynamic property

- Deprecated: Creation of dynamic property page::$index is deprecated in /usr/share/phpldapadmin/lib/page.php on line 38
- Deprecated: Creation of dynamic property page::$sysmsg is deprecated in /usr/share/phpldapadmin/lib/page.php on line 468
- Deprecated: Creation of dynamic property page::$_block is deprecated in /usr/share/phpldapadmin/lib/page.php on line 241
- Creation of dynamic property Template::$askcontainer is deprecated
- On import feature
- On export feature
- And others..

Origin: vendor
Forwarded: no
---
 lib/Query.php            | 1 +
 lib/Template.php         | 1 +
 lib/TemplateRender.php   | 2 ++
 lib/import_functions.php | 1 +
 lib/page.php             | 1 +
 5 files changed, 6 insertions(+)

diff --git a/lib/Query.php b/lib/Query.php
index cc2a4f3..cbfc77d 100644
--- a/lib/Query.php
+++ b/lib/Query.php
@@ -12,6 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Queries
  */
+#[\AllowDynamicProperties]
 class Query extends xmlTemplate {
 	protected $description = '';
 	public $results = array();
diff --git a/lib/Template.php b/lib/Template.php
index 2e4978f..5309193 100644
--- a/lib/Template.php
+++ b/lib/Template.php
@@ -28,6 +28,7 @@
  * @todo RDN attributes need to be checked that are included in the schema, otherwise mark it is invalid
  * @todo askcontainer is no longer used?
  */
+#[\AllowDynamicProperties]
 class Template extends xmlTemplate {
 	# If this template visible on the template choice list
 	private $visible = true;
diff --git a/lib/TemplateRender.php b/lib/TemplateRender.php
index b19d764..d273e35 100644
--- a/lib/TemplateRender.php
+++ b/lib/TemplateRender.php
@@ -15,6 +15,8 @@
 class TemplateRender extends PageRender {
 	# Page number
 	private $pagelast;
+	private $url_base;
+	private $layout;
 
 	/** CORE FUNCTIONS **/
 
diff --git a/lib/import_functions.php b/lib/import_functions.php
index 23a52f4..2c83149 100644
--- a/lib/import_functions.php
+++ b/lib/import_functions.php
@@ -144,6 +144,7 @@ abstract class Import {
  * @package phpLDAPadmin
  * @subpackage Import
  */
+#[\AllowDynamicProperties]
 class ImportLDIF extends Import {
 	private $_currentLineNumber = 0;
 	private $_currentLine = '';
diff --git a/lib/page.php b/lib/page.php
index fef5377..5053e9c 100644
--- a/lib/page.php
+++ b/lib/page.php
@@ -12,6 +12,7 @@
  * @package phpLDAPadmin
  * @subpackage Page
  */
+#[\AllowDynamicProperties]
 class page {
 	# pre-HTML headers
 	protected $_pageheader;
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 16:23:28 +0100
Subject: Fix PHP 8 error reporting detection

Origin: vendor
Forwarded: no

Ref: https://github.com/phpmyadmin/phpmyadmin/issues/16729#issuecomment-797664051
Ref: https://php.watch/versions/8.0/fatal-error-suppression
Ref: https://www.php.net/manual/fr/function.error-reporting.php#125674
Ref: https://www.php.net/manual/en/migration80.incompatible.php
---
 lib/functions.php | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/functions.php b/lib/functions.php
index 5746aa5..367385c 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -130,12 +130,13 @@ function app_error_handler($errno,$errstr,$file,$lineno) {
 		debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
 	/**
-	 * error_reporting will be 0 if the error context occurred
-	 * within a function call with '@' preprended (ie, @ldap_bind() );
+	 * error_reporting will be only the non-ignorable error number bits
+	 * if the error context occurred within a function call with '@'
+	 * preprended (ie, @ldap_bind() );
 	 * So, don't report errors if the caller has specifically
 	 * disabled them with '@'
 	 */
-	if (ini_get('error_reporting') == 0 || error_reporting() == 0)
+	if (!(ini_get('error_reporting') & error_reporting() & $errno))
 		return;
 
 	$file = basename($file);
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 16:09:20 +0100
Subject: Do not call get_magic_quote_gpc() when running in PHP version >=
 5.4.

This deprecated function has been removed in PHP 8.

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/3ec9c23d585826aa29f5f25ac43ca077f5fe5377
---
 lib/common.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/common.php b/lib/common.php
index 1ab1672..126aadc 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -296,7 +296,9 @@ if ($app['language'] == 'auto') {
  * Strip slashes from GET, POST, and COOKIE variables if this
  * PHP install is configured to automatically addslashes()
  */
-if (@get_magic_quotes_gpc() && (! isset($slashes_stripped) || ! $slashes_stripped)) {
+if (@version_compare(phpversion(), '5.4.0', '<') &&
+    @get_magic_quotes_gpc() &&
+    (!isset($slashes_stripped) || !$slashes_stripped)) {
 	array_stripslashes($_REQUEST);
 	array_stripslashes($_GET);
 	array_stripslashes($_POST);
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 17:31:38 +0100
Subject: Fix LDAP connect is a class on PHP 8.1 and not a resource anymore

Ref: https://www.php.net/manual/en/function.ldap-connect.php#refsect1-function.ldap-connect-changelog

In 8.1.0 -> Returns an LDAP\Connection instance now; previously, a resource was returned.
---
 lib/ds_ldap.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/ds_ldap.php b/lib/ds_ldap.php
index 9537ff2..f465207 100644
--- a/lib/ds_ldap.php
+++ b/lib/ds_ldap.php
@@ -216,7 +216,7 @@ class ldap extends DS {
 			debug_log('LDAP Resource [%s], Host [%s], Port [%s]',16,0,__FILE__,__LINE__,__METHOD__,
 				$resource,$this->getValue('server','host'),$this->getValue('server','port'));
 
-		if (! is_resource($resource))
+		if (! $resource instanceof \LDAP\Connection)
 			debug_dump_backtrace('UNHANDLED, $resource is not a resource',1);
 
 		# Go with LDAP version 3 if possible (needed for renaming and Novell schema fetching)
@@ -337,7 +337,7 @@ class ldap extends DS {
 		$connect = $this->connect($method,false,$new);
 
 		# If we didnt log in...
-		if (! is_resource($connect) || $this->noconnect || ! $this->userIsAllowedLogin($userDN)) {
+		if (! $connect instanceof \LDAP\Connection || $this->noconnect || ! $this->userIsAllowedLogin($userDN)) {
 			$this->logout($method);
 
 			return false;
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 16:06:13 +0100
Subject: Fix Mandatory function arguments must be listed before optional ones

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/3a75a321000150e9af89bf45fc5f60d8198e9157
---
 htdocs/collapse.php       | 2 +-
 htdocs/draw_tree_node.php | 2 +-
 htdocs/expand.php         | 2 +-
 htdocs/refresh.php        | 2 +-
 lib/PageRender.php        | 8 ++++----
 lib/Tree.php              | 2 +-
 lib/ds_ldap.php           | 8 ++++----
 lib/ds_ldap_pla.php       | 6 +++---
 lib/functions.php         | 8 ++++----
 lib/xmlTemplates.php      | 2 +-
 10 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/htdocs/collapse.php b/htdocs/collapse.php
index 8fb2731..c1ec07f 100644
--- a/htdocs/collapse.php
+++ b/htdocs/collapse.php
@@ -19,7 +19,7 @@ $dn = get_request('dn','GET',true);
 $tree = get_cached_item($app['server']->getIndex(),'tree');
 $entry = $tree->getEntry($dn);
 $entry->close();
-set_cached_item($app['server']->getIndex(),'tree','null',$tree);
+set_cached_item($app['server']->getIndex(),$tree,'tree','null');
 
 header(sprintf('Location:index.php?server_id=%s&junk=%s#%s%s',
 	$app['server']->getIndex(),random_junk(),htmlid($app['server']->getIndex(),$dn),app_session_param()));
diff --git a/htdocs/draw_tree_node.php b/htdocs/draw_tree_node.php
index 7311e2d..12ed6ee 100644
--- a/htdocs/draw_tree_node.php
+++ b/htdocs/draw_tree_node.php
@@ -50,7 +50,7 @@ if ($request['dn']) {
 }
 
 if ($treesave)
-	set_cached_item($app['server']->getIndex(),'tree','null',$tree);
+	set_cached_item($app['server']->getIndex(),$tree,'tree','null');
 
 if ($request['dn'])
 	echo $tree->draw_children($dnentry,$request['code']);
diff --git a/htdocs/expand.php b/htdocs/expand.php
index d0647d0..3600f00 100644
--- a/htdocs/expand.php
+++ b/htdocs/expand.php
@@ -19,7 +19,7 @@ $dn = get_request('dn','GET',true);
 $tree = get_cached_item($app['server']->getIndex(),'tree');
 $entry = $tree->getEntry($dn);
 $entry->open();
-set_cached_item($app['server']->getIndex(),'tree','null',$tree);
+set_cached_item($app['server']->getIndex(),$tree,'tree','null');
 
 header(sprintf('Location:index.php?server_id=%s&junk=%s#%s%s',
 	$app['server']->getIndex(),random_junk(),htmlid($app['server']->getIndex(),$dn),app_session_param()));
diff --git a/htdocs/refresh.php b/htdocs/refresh.php
index 385c4c6..120ce7a 100644
--- a/htdocs/refresh.php
+++ b/htdocs/refresh.php
@@ -34,7 +34,7 @@ if (get_request('purge','REQUEST')) {
 		$entry->open();
 	}
 
-	set_cached_item($app['server']->getIndex(),'tree','null',$tree);
+	set_cached_item($app['server']->getIndex(),$tree,'tree','null');
 }
 
 if (get_request('meth','REQUEST') == 'ajax') 
diff --git a/lib/PageRender.php b/lib/PageRender.php
index d905c96..f3c4169 100644
--- a/lib/PageRender.php
+++ b/lib/PageRender.php
@@ -827,7 +827,7 @@ class PageRender extends Visitor {
 		if (! $attribute->getOldValue($i))
 			return;
 
-		draw_jpeg_photo($this->getServer(),$this->template->getDN(),$attribute->getName(),$i,false,false);
+		draw_jpeg_photo($this->getServer(),$this->template->getDN(),$i,$attribute->getName(),false,false);
 	}
 
 	/**
@@ -844,16 +844,16 @@ class PageRender extends Visitor {
 		# If the attribute is modified, the new value needs to be stored in a session variable for the draw_jpeg_photo callback.
 		if ($attribute->hasBeenModified()) {
 			$_SESSION['tmp'][$attribute->getName()][$i] = $attribute->getValue($i);
-			draw_jpeg_photo(null,$this->template->getDN(),$attribute->getName(),$i,false,false);
+			draw_jpeg_photo(null,$this->template->getDN(),$i,$attribute->getName(),false,false);
 		} else
-			draw_jpeg_photo($this->getServer(),$this->template->getDN(),$attribute->getName(),$i,false,false);
+			draw_jpeg_photo($this->getServer(),$this->template->getDN(),$i,$attribute->getName(),false,false);
 	}
 
 	protected function drawFormReadOnlyValueJpegAttribute($attribute,$i) {
 		$this->draw('HiddenValue',$attribute,$i);
 		$_SESSION['tmp'][$attribute->getName()][$i] = $attribute->getValue($i);
 
-		draw_jpeg_photo(null,$this->template->getDN(),$attribute->getName(),$i,false,false);
+		draw_jpeg_photo(null,$this->template->getDN(),$i,$attribute->getName(),false,false);
 	}
 
 	protected function drawFormReadOnlyValueMultiLineAttribute($attribute,$i) {
diff --git a/lib/Tree.php b/lib/Tree.php
index e7542fc..f18ba36 100644
--- a/lib/Tree.php
+++ b/lib/Tree.php
@@ -68,7 +68,7 @@ abstract class Tree {
 				}
 			}
 
-			set_cached_item($server_id,'tree','null',$tree);
+			set_cached_item($server_id,$tree,'tree','null');
 		}
 
 		return $tree;
diff --git a/lib/ds_ldap.php b/lib/ds_ldap.php
index a477efc..faa8478 100644
--- a/lib/ds_ldap.php
+++ b/lib/ds_ldap.php
@@ -1768,7 +1768,7 @@ class ldap extends DS {
 			ksort($return);
 
 			# cache the schema to prevent multiple schema fetches from LDAP server
-			set_cached_item($this->index,'schema','objectclasses',$return);
+			set_cached_item($this->index,$return,'schema','objectclasses');
 		}
 
 		if (DEBUG_ENABLED)
@@ -1953,7 +1953,7 @@ class ldap extends DS {
 			$return = $attrs;
 
 			# cache the schema to prevent multiple schema fetches from LDAP server
-			set_cached_item($this->index,'schema','attributes',$return);
+			set_cached_item($this->index,$return,'schema','attributes');
 		}
 
 		if (DEBUG_ENABLED)
@@ -2029,7 +2029,7 @@ class ldap extends DS {
 			$return = $rules;
 
 			# cache the schema to prevent multiple schema fetches from LDAP server
-			set_cached_item($this->index,'schema','matchingrules',$return);
+			set_cached_item($this->index,$return,'schema','matchingrules');
 		}
 
 		if (DEBUG_ENABLED)
@@ -2078,7 +2078,7 @@ class ldap extends DS {
 			ksort($return);
 
 			# cache the schema to prevent multiple schema fetches from LDAP server
-			set_cached_item($this->index,'schema','syntaxes',$return);
+			set_cached_item($this->index,$return,'schema','syntaxes');
 		}
 
 		if (DEBUG_ENABLED)
diff --git a/lib/ds_ldap_pla.php b/lib/ds_ldap_pla.php
index fdc8048..8a10905 100644
--- a/lib/ds_ldap_pla.php
+++ b/lib/ds_ldap_pla.php
@@ -371,7 +371,7 @@ class ldap_pla extends ldap {
 
 				$tree->addEntry($dn);
 
-				set_cached_item($this->index,'tree','null',$tree);
+				set_cached_item($this->index,$tree,'tree','null');
 
 				run_hook('post_entry_create',array('server_id'=>$this->index,'method'=>$method,'dn'=>$dn,'attrs'=>$entry_array));
 
@@ -403,7 +403,7 @@ class ldap_pla extends ldap {
 				$tree = get_cached_item($this->index,'tree');
 				$tree->delEntry($dn);
 
-				set_cached_item($this->index,'tree','null',$tree);
+				set_cached_item($this->index,$tree,'tree','null');
 
 				run_hook('post_entry_delete',array('server_id'=>$this->index,'method'=>$method,'dn'=>$dn));
 			}
@@ -430,7 +430,7 @@ class ldap_pla extends ldap {
 				$newdn = sprintf('%s,%s',$new_rdn,$container);
 				$tree->renameEntry($dn,$newdn);
 
-				set_cached_item($this->index,'tree','null',$tree);
+				set_cached_item($this->index,$tree,'tree','null');
 
 				run_hook('post_entry_rename',array('server_id'=>$this->index,'method'=>$method,'dn'=>$dn,'rdn'=>$new_rdn,'container'=>$container));
 			}
diff --git a/lib/functions.php b/lib/functions.php
index b44dd2c..5746aa5 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -928,7 +928,7 @@ function get_cached_item($index,$item,$subitem='null') {
  *
  * Returns true on success of false on failure.
  */
-function set_cached_item($index,$item,$subitem='null',$data) {
+function set_cached_item($index,$data,$item,$subitem='null') {
 	if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 		debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
@@ -2032,8 +2032,8 @@ function ldap_error_msg($msg,$errnum) {
  *
  * Usage Examples:
  *  <code>
- *   draw_jpeg_photo(0,'cn=Bob,ou=People,dc=example,dc=com',"jpegPhoto",0,true,array('img_opts'=>"border: 1px; width: 150px"));
- *   draw_jpeg_photo(1,'cn=Fred,ou=People,dc=example,dc=com',null,1);
+ *   draw_jpeg_photo(0,'cn=Bob,ou=People,dc=example,dc=com',0,"jpegPhoto",true,array('img_opts'=>"border: 1px; width: 150px"));
+ *   draw_jpeg_photo(1,'cn=Fred,ou=People,dc=example,dc=com',1,null);
  *  </code>
  *
  * @param object The Server to get the image from.
@@ -2046,7 +2046,7 @@ function ldap_error_msg($msg,$errnum) {
  * @param array Specifies optional image and CSS style attributes for the table tag. Supported keys are
  *                fixed_width, fixed_height, img_opts.
  */
-function draw_jpeg_photo($server,$dn,$attr_name='jpegphoto',$index,$draw_delete_buttons=false,$options=array()) {
+function draw_jpeg_photo($server,$dn,$index,$attr_name='jpegphoto',$draw_delete_buttons=false,$options=array()) {
 	if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 		debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
diff --git a/lib/xmlTemplates.php b/lib/xmlTemplates.php
index 1749bac..f55e876 100644
--- a/lib/xmlTemplates.php
+++ b/lib/xmlTemplates.php
@@ -140,7 +140,7 @@ abstract class xmlTemplates {
 
 		if ($changed) {
 			masort($this->templates,'title');
-			set_cached_item($server_id,$class['item'],'null',$this->templates);
+			set_cached_item($server_id,$this->templates,$class['item'],'null');
 		}
 	}
 
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 15:51:28 +0100
Subject: Fix memorylimit warning

I did not change the system_message part as it changes the message,  it's not needed for this patch

Ref: https://github.com/leenooks/phpLDAPadmin/pull/180#discussion_r1141029893

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/15cc6f538203de858093a69b7f84ec7d20f4c4d6
---
 lib/config_default.php |  2 +-
 lib/functions.php      | 35 +++++++++++++++++++++++++++++------
 2 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/lib/config_default.php b/lib/config_default.php
index 121d743..ea776b2 100644
--- a/lib/config_default.php
+++ b/lib/config_default.php
@@ -504,7 +504,7 @@ class Config {
 
 		$this->default->session['memorylimit'] = array(
 			'desc'=>'Set the PHP memorylimit warning threshold.',
-			'default'=>24);
+			'default'=>'24M');
 
 		$this->default->session['timelimit'] = array(
 			'desc'=>'Set the PHP timelimit.',
diff --git a/lib/functions.php b/lib/functions.php
index 367385c..8e8c63a 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -332,16 +332,39 @@ function check_config($config_file) {
 	$config->setServers($servers);
 
 	# Check the memory limit parameter.
-	if ((ini_get('memory_limit') > -1) && ini_get('memory_limit') < $config->getValue('session','memorylimit'))
-		system_message(array(
-			'title'=>_('Memory Limit low.'),
-			'body'=>sprintf('Your php memory limit is low - currently %s, you should increase it to atleast %s. This is normally controlled in /etc/php.ini.',
-				ini_get('memory_limit'),$config->getValue('session','memorylimit')),
-			'type'=>'error'));
+	$limit = memory_str_to_int(ini_get('memory_limit'));
+	if ($limit != -1) {
+		$threshold = memory_str_to_int($config->getValue('session','memorylimit'));
+		if ($limit < $threshold) {
+			system_message(array(
+				'title'=>_('Memory Limit low.'),
+				'body'=>sprintf('Your php memory limit is low - currently %s, you should increase it to atleast %s. This is normally controlled in /etc/php.ini.',
+					ini_get('memory_limit'),$config->getValue('session','memorylimit')),
+				'type'=>'error'));
+
+		}
+	}
 
 	return $config;
 }
 
+/**
+ * Converts shorthand memory notation string to an integer that represents the
+ * given amount in bytes (ie. "128M" -> 134217728).
+ *
+ * @param string $value
+ * @return int
+ */
+function memory_str_to_int(string $value) {
+    $value = trim(strtolower($value));
+    if (intval($value) > 0 && preg_match('/^(\d+)([kmg])?$/', $value, $match, PREG_UNMATCHED_AS_NULL)) {
+        [$int, $mod] = [intval($match[1]), $match[2]];
+        $pow = [NULL => 0, 'k' => 1, 'm' => 2, 'g' => 3][$mod];
+        return $int * 1024 ** $pow;
+    }
+    return intval($value);
+}
+
 /**
  * Commands available in the control_panel of the page
  *
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 16:50:06 +0100
Subject: Fix openssl 3 PHP 8 cipher method

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/pull/176/commits/661cab652b279680c07e81b4b71d1955ee2818ab
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/ef8d0ce94cbb5f17f5a0b25b9bc571e8eb8c5419
---
 lib/functions.php | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/functions.php b/lib/functions.php
index c8e509c..eb5b5dd 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -792,9 +792,9 @@ function blowfish_encrypt($data,$secret=null) {
 	if (! trim($secret))
 		return $data;
 
-	if (! empty($data) && function_exists('openssl_encrypt') && in_array('bf-ecb', openssl_get_cipher_methods())) {
-		$keylen = openssl_cipher_iv_length('bf-ecb') * 2;
-		return openssl_encrypt($data, 'bf-ecb', substr($secret,0,$keylen));
+	if (! empty($data) && function_exists('openssl_encrypt') && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
+		$keylen = openssl_cipher_iv_length('aes-256-gcm') * 2;
+		return openssl_encrypt($data, 'aes-256-gcm', substr($secret,0,$keylen));
 	}
 
 	if (function_exists('mcrypt_module_open') && ! empty($data)) {
@@ -853,9 +853,9 @@ function blowfish_decrypt($encdata,$secret=null) {
 	if (! trim($secret))
 		return $encdata;
 
-	if (! empty($encdata) && function_exists('openssl_encrypt') && in_array('bf-ecb', openssl_get_cipher_methods())) {
-		$keylen = openssl_cipher_iv_length('bf-ecb') * 2;
-		return trim(openssl_decrypt($encdata, 'bf-ecb', substr($secret,0,$keylen)));
+	if (! empty($encdata) && function_exists('openssl_encrypt') && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
+		$keylen = openssl_cipher_iv_length('aes-256-gcm') * 2;
+		return trim(openssl_decrypt($encdata, 'aes-256-gcm', substr($secret,0,$keylen)));
 	}
 
 	if (function_exists('mcrypt_module_open') && ! empty($encdata)) {
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 17:21:40 +0100
Subject: Fix openssl IV "openssl_encrypt(): Setting of IV length for AEAD
 mode failed"

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/issues/183#issuecomment-1450893271
---
 lib/functions.php | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/functions.php b/lib/functions.php
index eb5b5dd..9d38cdf 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -21,6 +21,7 @@ define('TMPLDIR',sprintf('%s/',realpath(LIBDIR.'../templates/')));
 define('DOCDIR',sprintf('%s/',realpath(LIBDIR.'../doc/')));
 define('HOOKSDIR',sprintf('%s/',realpath(LIBDIR.'../hooks/')));
 define('JSDIR','js/');
+define('SESSION_CIPHER', 'aes-256-gcm');
 
 /**
  * Supplimental functions
@@ -792,9 +793,11 @@ function blowfish_encrypt($data,$secret=null) {
 	if (! trim($secret))
 		return $data;
 
-	if (! empty($data) && function_exists('openssl_encrypt') && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
-		$keylen = openssl_cipher_iv_length('aes-256-gcm') * 2;
-		return openssl_encrypt($data, 'aes-256-gcm', substr($secret,0,$keylen));
+	if (! empty($data) && function_exists('openssl_encrypt') && in_array(SESSION_CIPHER, openssl_get_cipher_methods())) {
+		$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(SESSION_CIPHER));
+		$keylen = openssl_cipher_iv_length(SESSION_CIPHER) * 2;
+		$encrypted = openssl_encrypt($data, SESSION_CIPHER, substr($secret,0,$keylen), $options=0, $iv, $tag);
+		return base64_encode($encrypted . '::' . $iv . '::' . $tag);
 	}
 
 	if (function_exists('mcrypt_module_open') && ! empty($data)) {
@@ -853,9 +856,10 @@ function blowfish_decrypt($encdata,$secret=null) {
 	if (! trim($secret))
 		return $encdata;
 
-	if (! empty($encdata) && function_exists('openssl_encrypt') && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
-		$keylen = openssl_cipher_iv_length('aes-256-gcm') * 2;
-		return trim(openssl_decrypt($encdata, 'aes-256-gcm', substr($secret,0,$keylen)));
+	if (! empty($encdata) && function_exists('openssl_encrypt') && in_array(SESSION_CIPHER, openssl_get_cipher_methods())) {
+		$keylen = openssl_cipher_iv_length(SESSION_CIPHER) * 2;
+		list($encryptedData, $iv, $tag) = explode('::', base64_decode($encdata), 3);
+		return trim(openssl_decrypt($encryptedData, SESSION_CIPHER, substr($secret,0,$keylen), $options=0, $iv, $tag));
 	}
 
 	if (function_exists('mcrypt_module_open') && ! empty($encdata)) {
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 18:16:07 +0100
Subject: Fix strftime is deprecated on PHP 8.1

Origin: vendor
Forwarded: no
---
 lib/HTMLTree.php   | 2 +-
 lib/PageRender.php | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/HTMLTree.php b/lib/HTMLTree.php
index e96a254..a036bc8 100644
--- a/lib/HTMLTree.php
+++ b/lib/HTMLTree.php
@@ -170,7 +170,7 @@ class HTMLTree extends Tree {
 
 		if (! is_null($server->inactivityTime())) {
 			$m = sprintf(_('Inactivity will log you off at %s'),
-				strftime('%H:%M',$server->inactivityTime()));
+				@strftime('%H:%M',$server->inactivityTime()));
 			printf(' <img width="14" height="14" src="%s/timeout.png" title="%s" alt="%s"/>',IMGDIR,$m,'Timeout');
 		}
 		echo '</td></tr>';
diff --git a/lib/PageRender.php b/lib/PageRender.php
index 479f9ec..3da01d2 100644
--- a/lib/PageRender.php
+++ b/lib/PageRender.php
@@ -1214,15 +1214,15 @@ class PageRender extends Visitor {
 		echo '<br/><small>';
 		if (($today < $shadow_date) && in_array(strtolower($attribute->getName()),$shadow_before_today_attrs))
 			printf('<span style="color:red">(%s)</span>',
-				strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
+				@strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
 
 		elseif (($today > $shadow_date) && in_array(strtolower($attribute->getName()),$shadow_after_today_attrs))
 			printf('<span style="color:red">(%s)</span>',
-				strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
+				@strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
 
 		else
 			printf('(%s)',
-				strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
+				@strftime($_SESSION[APPCONFIG]->getValue('appearance','date'),$shadow_date));
 
 		echo '</small><br />';
 	}
From: William Desportes <william...@wdes.fr>
Date: Sat, 18 Mar 2023 15:42:04 +0100
Subject: Fix trim(): Passing null to parameter #1  is deprecated

- Unrecognized error number: 8192: trim(): Passing null to parameter #1 ($string) of type string is deprecated

Origin: upstream
Forwarded: https://github.com/leenooks/phpLDAPadmin/commit/9488fe2ed7841bffc322c6c9afeb9fc3e2bd0a42
---
 htdocs/cmd.php | 2 +-
 lib/ds.php     | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/htdocs/cmd.php b/htdocs/cmd.php
index 0ddf004..8a9d089 100644
--- a/htdocs/cmd.php
+++ b/htdocs/cmd.php
@@ -41,7 +41,7 @@ if (DEBUG_ENABLED)
 $www['page'] = new page($app['server']->getIndex());
 
 # See if we can render the command
-if (trim($www['cmd'])) {
+if ($www['cmd'] && trim($www['cmd'])) {
 	# If this is a READ-WRITE operation, the LDAP server must not be in READ-ONLY mode.
 	if ($app['server']->isReadOnly() && ! in_array(get_request('cmd','REQUEST'),$app['readwrite_cmds']))
 		error(_('You cannot perform updates while server is in read-only mode'),'error','index.php');
diff --git a/lib/ds.php b/lib/ds.php
index 31700d3..d54099e 100644
--- a/lib/ds.php
+++ b/lib/ds.php
@@ -437,7 +437,8 @@ abstract class DS {
 		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
 			debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
 
-		if (! trim($this->getLogin(null)) && $_SESSION[APPCONFIG]->getValue('appearance','anonymous_bind_implies_read_only'))
+		$login = $this->getLogin(null);
+		if (!($login && trim($login)) && $_SESSION[APPCONFIG]->getValue('appearance','anonymous_bind_implies_read_only'))
 			return true;
 		else
 			return $this->getValue('server','read_only');
Fix-Mandatory-function-arguments.patch
Fix-get_magic_quote_gpc-PHP-7.patch
Fix-error-reporting-detection-PHP-8.patch
Fix-memorylimit-warning-PHP-8.patch
Fix-deprecated-float-conversion-PHP-8.patch
Fix-trim-null-PHP-8.patch
Fix-deprecated-code-PHP-8.1.patch
Fix-class-name-builtin-clash-PHP-8.patch
Fix-openssl-3-cipher-name-PHP-8.patch
Fix-openssl-IV-length-PHP-8.patch
Fix-ldap-connect-PHP-8.1-is-now-a-class.patch
Fix-strftime-is-deprecated-PHP-8.1.patch
Fix-dynamic-property-PHP-8.2.patch

Reply via email to