*/ protected static $attributes_to_entry_types = array( 'attributeTypes' => 'Attribute', 'matchingRules' => 'MatchingRule', 'matchingRuleUse' => 'MatchingRuleUse', 'objectClasses' => 'ObjectClass', 'ldapSyntaxes' => 'Syntax', ); /** * Loaded schema entries ordered by type * @var array> */ protected $entries = array(); /** * Loaded schema entries mapped with their OID * @var array */ protected $oids = array(); /** * Loaded telltale * @var bool */ protected $loaded = false; /** * Constructor * @param Ldap $ldap The LDAP connection * @param Entry $entry The cn=SubSchema LDAP entry object * @return void */ public function __construct(&$ldap, &$entry) { $this -> ldap = $ldap; $this -> entry = $entry; $this -> parse(); $this -> loaded = true; } /** * Magic method to get schema key * @param string $key * @return mixed * @throws \EesyLDAP\InvalidPropertyException */ public function __get($key) { switch ($key) { case 'loaded': return $this -> loaded; } throw new \EesyLDAP\InvalidPropertyException( "Invalid property '$key' requested on '".get_called_class()."'" ); } /** * Load schema from provided LDAP connection * @param Ldap $ldap * @param bool|null $raise * @return Schema|false Schema object on success, false on error */ public static function load(&$ldap, $raise=null) { $entry = $ldap->get_entry( 'cn=SubSchema', '(objectclass=*)', array_keys(self :: $attributes_to_entry_types) ); if (!$entry instanceof Entry) return $ldap->error('Fail to load cn=SubSchema entry', $raise); return new Schema($ldap, $entry); } /** * Parse SubSchema entry attributes values * @return void */ protected function parse() { foreach (self :: $attributes_to_entry_types as $attr => $type) { $type_name = strtolower($type); foreach($this -> entry -> get_raw_values($attr, array(), true) as $value) { // @phpstan-ignore-next-line $entry = call_user_func("\\EesyLDAP\\Schema\\$type::parse", $value); if (!$entry instanceof Schema\SchemaEntry) { $this -> ldap -> error("Fail to parse %s schema value: %s", null, $attr, $value); continue; } $oid = $entry->oid; if ($type != 'MatchingRuleUse') { if (array_key_exists($oid, $this->oids)) { $this -> ldap -> error( "Duplicate OID %s found in schema: %s / %s", null, $oid, $this->oids[$oid], $entry); continue; } $this->oids[$oid] = $entry; } if (!array_key_exists($type_name, $this -> entries)) $this -> entries[$type_name] = array(); $name = $entry->name; if (array_key_exists($name, $this -> entries[$type_name])) { $this -> ldap -> error( "Duplicate %s schema entry %s found: %s / %s", null, $type, $name, $this -> entries[$type_name][$name], $entry ); continue; } $this -> entries[$type_name][$name] = $entry; } } } /** * Get a schema entry by type and name/oid * @param string $type * @param string $name_or_oid * @return Schema\SchemaEntry|false */ protected function _get_entry($type, $name_or_oid) { if ( array_key_exists($name_or_oid, $this -> oids) && is_a($this -> oids[$name_or_oid], "\\EesyLDAP\\Schema\\$type") ) return $this -> oids[$name_or_oid]; $type_name = strtolower($type); if (!array_key_exists($type_name, $this -> entries)) return false; foreach($this -> entries[$type_name] as $attr) if ($attr->is_me($name_or_oid)) return $attr; return false; } /** * Get an attribute by name or oid * @param string $name_or_oid * @return Schema\Attribute|false */ public function attribute($name_or_oid) { // @phpstan-ignore-next-line return $this -> _get_entry('Attribute', $name_or_oid); } /** * Get an objectclass by name or oid * @param string $name_or_oid * @return \EesyLDAP\Schema\ObjectClass|false */ public function objectclass($name_or_oid) { // @phpstan-ignore-next-line return $this -> _get_entry('ObjectClass', $name_or_oid); } /** * Get a matching rule by name or oid * @param string $name_or_oid * @return Schema\MatchingRule|false */ public function matching_rule($name_or_oid) { // @phpstan-ignore-next-line return $this -> _get_entry('MatchingRule', $name_or_oid); } /** * Get a matching rule use by name or oid * @param string $name_or_oid * @return Schema\MatchingRuleUse|false */ public function matching_rule_use($name_or_oid) { // @phpstan-ignore-next-line return $this -> _get_entry('MatchingRuleUse', $name_or_oid); } /** * Get a syntax by name or oid * @param string $name_or_oid * @return Schema\Syntax|false */ public function syntax($name_or_oid) { // @phpstan-ignore-next-line return $this -> _get_entry('Syntax', $name_or_oid); } /** * Check if given objectclass have the specified attribute * @param string $attr The attribute name * @param string|array $objectclasses List of objectclass * @return bool */ public function has_attribute($attr, ...$objectclasses) { foreach($objectclasses as $objectclass) { if (is_array($objectclass)) { if (call_user_func_array(array($this, 'has_attribute'), array_merge(array($attr), $objectclass))) return true; continue; } $oc = $this -> objectclass($objectclass); if (!$oc) continue; if ($oc->has_attribute($attr)) return true; } return false; } }