2024-04-04 22:21:20 +04:00
|
|
|
<?php
|
|
|
|
namespace nur\ldap;
|
|
|
|
|
|
|
|
use ArrayAccess;
|
|
|
|
use Countable;
|
|
|
|
use Iterator;
|
|
|
|
use nur\A;
|
|
|
|
use nur\b\coll\TIterableArray;
|
|
|
|
use nur\ldap\syntaxes\AbstractSyntax;
|
|
|
|
use nur\str;
|
|
|
|
|
|
|
|
class LdapAttr implements ArrayAccess, Countable, Iterator {
|
|
|
|
use TIterableArray;
|
|
|
|
|
|
|
|
const MONOVALUED = 1, BINARY = 2, ORDERED = 4, NOT_HUMAN_READABLE = 8;
|
|
|
|
|
|
|
|
function __construct(string $name, ?array &$values, ?AbstractSyntax $syntax, ?int $flags) {
|
|
|
|
$this->name = $name;
|
|
|
|
$this->syntax = $syntax;
|
|
|
|
$this->flags = $flags;
|
|
|
|
$this->reset($values);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
protected $name;
|
|
|
|
|
|
|
|
function name(): string {
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var ?array */
|
|
|
|
protected $data;
|
|
|
|
|
|
|
|
function reset(?array &$values): self {
|
|
|
|
$this->data =& $values;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var AbstractSyntax */
|
|
|
|
protected $syntax;
|
|
|
|
|
|
|
|
/** @var int */
|
|
|
|
protected $flags;
|
|
|
|
|
|
|
|
function isMonovalued(): bool {
|
|
|
|
return $this->flags !== null && $this->flags & self::MONOVALUED != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isBinary(): bool {
|
|
|
|
return $this->flags !== null && $this->flags & self::BINARY != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isOrdered(): bool {
|
|
|
|
return $this->flags !== null && $this->flags & self::ORDERED != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isNotHumanReadable(): bool {
|
|
|
|
return $this->flags !== null && $this->flags & self::NOT_HUMAN_READABLE != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function fromLdap($value) {
|
|
|
|
$syntax = $this->syntax;
|
|
|
|
if ($syntax !== null) {
|
|
|
|
if ($this->isMonovalued()) $value = $syntax->fromMonovaluedLdap($value);
|
|
|
|
else $value = $syntax->fromMultivaluedLdap($value);
|
|
|
|
}
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
protected function fromPhp($value): ?iterable {
|
|
|
|
$syntax = $this->syntax;
|
|
|
|
if ($syntax !== null) $value = $syntax->fromPhp($value);
|
|
|
|
else A::ensure_narray($value);
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner un tableau si multivalué, une valeur scalaire si monovalué */
|
|
|
|
function get($index=null) {
|
|
|
|
$value = $this->fromLdap($this->data);
|
|
|
|
if ($index !== null && is_array($value)) {
|
|
|
|
$value = array_key_exists($index, $value)? $value[$index]: null;
|
|
|
|
}
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* retourner toutes les valeurs
|
|
|
|
*
|
|
|
|
* @param string $checkPrefixDel ne retourner que les valeurs qui commencent
|
|
|
|
* par ce préfixe ET enlever le préfixe
|
|
|
|
*/
|
|
|
|
function all(?string $checkPrefixDel=null): ?array {
|
|
|
|
if ($this->syntax === null) $values = $this->data;
|
|
|
|
else $values = $this->syntax->fromMultivaluedLdap($this->data);
|
2024-09-11 16:16:53 +04:00
|
|
|
if ($checkPrefixDel !== null && $values !== null) {
|
2024-04-04 22:21:20 +04:00
|
|
|
$filtered = [];
|
|
|
|
foreach ($values as $value) {
|
|
|
|
if (str::del_prefix($value, $checkPrefixDel)) {
|
|
|
|
$filtered[] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$values = $filtered;
|
|
|
|
}
|
|
|
|
return $values;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner la première valeur */
|
|
|
|
function first(?string $checkPrefixDel=null) {
|
|
|
|
return A::first($this->all($checkPrefixDel));
|
|
|
|
}
|
|
|
|
|
|
|
|
function set($values, bool $unlessNn=false): self {
|
|
|
|
if ($values instanceof LdapAttr) $values = $values->array();
|
|
|
|
if (!$unlessNn || $this->data === null) {
|
|
|
|
$this->data = $this->fromPhp($values);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static function in_array(string $needle, array $haystack, bool $strict, ?int &$index=null): bool {
|
|
|
|
if (!$strict) $needle = strtolower($needle);
|
|
|
|
foreach ($haystack as $index => $hay) {
|
|
|
|
if ($strict && $hay === $needle) return true;
|
|
|
|
if (!$strict && strtolower($hay) == $needle) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** vérifier si la valeur spécifiée figure dans l'attribut */
|
|
|
|
function contains($value, bool $strict=false): bool {
|
|
|
|
$value = A::first($this->fromPhp($value));
|
|
|
|
if ($value === null || $this->data === null) return false;
|
|
|
|
return self::in_array($value, $this->data, $strict);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* l'unicité est calculée ainsi:
|
|
|
|
* - en mode strict, ce doit être une égalité parfaite
|
|
|
|
* - en mode non strict, la comparaison est insensible à la casse
|
|
|
|
* XXX à terme, implémenter la comparaison en fonction de la syntaxe
|
|
|
|
*/
|
|
|
|
function add($value, bool $unique=true, bool $strict=false): self {
|
|
|
|
$value = A::first($this->fromPhp($value));
|
|
|
|
if ($value !== null) {
|
|
|
|
if (!$unique || $this->data === null ||
|
|
|
|
!self::in_array($value, $this->data, $strict)) {
|
|
|
|
$this->data[] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addAll(?iterable $values): self {
|
|
|
|
if ($values !== null) {
|
|
|
|
foreach ($values as $value) {
|
|
|
|
$this->add($value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
function del($value, int $maxCount=-1, bool $strict=false): self {
|
|
|
|
if ($value !== null && $this->data !== null) {
|
|
|
|
$value = A::first($this->fromPhp($value));
|
|
|
|
$rekey = false;
|
|
|
|
while ($maxCount != 0) {
|
|
|
|
if (!self::in_array($value, $this->data, $strict, $index)) break;
|
|
|
|
unset($this->data[$index]);
|
|
|
|
$rekey = true;
|
|
|
|
if ($maxCount > 0) $maxCount--;
|
|
|
|
}
|
|
|
|
if ($rekey) $this->data = array_values($this->data);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ins(int $index, $value): self {
|
|
|
|
$value = A::first($this->fromPhp($value));
|
|
|
|
if ($value !== null) {
|
|
|
|
A::insert($this->data, $index, $value);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
function unset(int $index): self {
|
|
|
|
if ($this->data !== null) {
|
|
|
|
$count = count($this->array());
|
|
|
|
if ($count > 0 && $index < 0) {
|
|
|
|
while ($index < 0) $index += $count;
|
|
|
|
}
|
|
|
|
unset($this->data[$index]);
|
|
|
|
$this->data = array_values($this->data);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
function key() { return $this->_key(); }
|
|
|
|
function current() {
|
|
|
|
$current = $this->_current();
|
|
|
|
$syntax = $this->syntax;
|
|
|
|
if ($syntax !== null) $current = $syntax->ldap2php($current);
|
|
|
|
return $current;
|
|
|
|
}
|
|
|
|
|
|
|
|
#############################################################################
|
|
|
|
# données au format LDAP
|
|
|
|
|
|
|
|
function __toString() {
|
|
|
|
return implode("\n", $this->data);
|
|
|
|
}
|
|
|
|
/** retourner les données au format LDAP */
|
|
|
|
function &array(): ?array { return $this->data; }
|
|
|
|
function count(): int { return count($this->data); }
|
|
|
|
function keys(): array { return array_keys($this->data); }
|
|
|
|
function offsetExists($key) {
|
|
|
|
return $this->data !== null && array_key_exists($key, $this->data);
|
|
|
|
}
|
|
|
|
function offsetGet($key) { return array_key_exists($key, $this->data)? $this->data[$key]: null; }
|
|
|
|
function offsetSet($key, $value) { $this->data[$key] = $value; }
|
|
|
|
function offsetUnset($key) { unset($this->data[$key]); }
|
|
|
|
|
|
|
|
function __isset($key) { return $this->offsetExists($key); }
|
|
|
|
function __get($key) { return $this->offsetGet($key); }
|
|
|
|
function __set($key, $value) { $this->offsetSet($key, $value); }
|
|
|
|
function __unset($key) { $this->offsetUnset($key); }
|
|
|
|
}
|