Net_LDAP
[ class tree: Net_LDAP ] [ index: Net_LDAP ] [ all elements ]

Source for file Schema.php

Documentation is available at Schema.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3.  
  4. require_once 'PEAR.php';
  5.  
  6. /**
  7. * Syntax definitions
  8. *
  9. * Please don't forget to add binary attributes to isBinary() below
  10. * to support proper value fetching from Net_LDAP_Entry
  11. */
  12. define('NET_LDAP_SYNTAX_BOOLEAN',            '1.3.6.1.4.1.1466.115.121.1.7');
  13. define('NET_LDAP_SYNTAX_DIRECTORY_STRING',   '1.3.6.1.4.1.1466.115.121.1.15');
  14. define('NET_LDAP_SYNTAX_DISTINGUISHED_NAME''1.3.6.1.4.1.1466.115.121.1.12');
  15. define('NET_LDAP_SYNTAX_INTEGER',            '1.3.6.1.4.1.1466.115.121.1.27');
  16. define('NET_LDAP_SYNTAX_JPEG',               '1.3.6.1.4.1.1466.115.121.1.28');
  17. define('NET_LDAP_SYNTAX_NUMERIC_STRING',     '1.3.6.1.4.1.1466.115.121.1.36');
  18. define('NET_LDAP_SYNTAX_OID',                '1.3.6.1.4.1.1466.115.121.1.38');
  19. define('NET_LDAP_SYNTAX_OCTET_STRING',       '1.3.6.1.4.1.1466.115.121.1.40');
  20.  
  21. /**
  22. * Load an LDAP Schema and provide information
  23. *
  24. * This class takes a Subschema entry, parses this information
  25. * and makes it available in an array. Most of the code has been
  26. * inspired by perl-ldap( http://perl-ldap.sourceforge.net).
  27. * You will find portions of their implementation in here.
  28. *
  29. @category Net
  30. @package  Net_LDAP
  31. @author   Jan Wagner <wagner@netsols.de>
  32. @author   Benedikt Hallinger <beni@php.net>
  33. @license  http://www.gnu.org/copyleft/lesser.html LGPL
  34. @version  CVS: $Id: Schema.php,v 1.22 2008/06/04 10:47:48 beni Exp $
  35. @link     http://pear.php.net/package/Net_LDAP/
  36. */
  37. class Net_LDAP_Schema extends PEAR
  38. {
  39.     /**
  40.     * Map of entry types to ldap attributes of subschema entry
  41.     *
  42.     * @access public
  43.     * @var array 
  44.     */
  45.     var $types = array('attribute'        => 'attributeTypes',
  46.                        'ditcontentrule'   => 'dITContentRules',
  47.                        'ditstructurerule' => 'dITStructureRules',
  48.                        'matchingrule'     => 'matchingRules',
  49.                        'matchingruleuse'  => 'matchingRuleUse',
  50.                        'nameform'         => 'nameForms',
  51.                        'objectclass'      => 'objectClasses',
  52.                        'syntax'           => 'ldapSyntaxes');
  53.  
  54.     /**
  55.     * Array of entries belonging to this type
  56.     *
  57.     * @access private
  58.     * @var array 
  59.     */
  60.     var $_attributeTypes    = array();
  61.     var $_matchingRules     = array();
  62.     var $_matchingRuleUse   = array();
  63.     var $_ldapSyntaxes      = array();
  64.     var $_objectClasses     = array();
  65.     var $_dITContentRules   = array();
  66.     var $_dITStructureRules = array();
  67.     var $_nameForms         = array();
  68.  
  69.  
  70.     /**
  71.     * hash of all fetched oids
  72.     *
  73.     * @access private
  74.     * @var array 
  75.     */
  76.     var $_oids = array();
  77.  
  78.     /**
  79.     * Tells if the schema is initialized
  80.     *
  81.     * @access private
  82.     * @var boolean 
  83.     * @see parse(), get()
  84.     */
  85.     var $_initialized = false;
  86.  
  87.  
  88.     /**
  89.     * constructor of the class
  90.     *
  91.     * @access protected
  92.     */
  93.     function Net_LDAP_Schema()
  94.     {
  95.         $this->PEAR('Net_LDAP_Error')// default error class
  96.     }
  97.  
  98.     /**
  99.     * Return a hash of entries for the given type
  100.     *
  101.     * Returns a hash of entry for th givene type. Types may be:
  102.     * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
  103.     * matchingruleuses, nameforms, syntaxes
  104.     *
  105.     * @param string $type Type to fetch
  106.     *
  107.     * @access public
  108.     * @return array|Net_LDAP_ErrorArray or Net_LDAP_Error
  109.     */
  110.     function &getAll($type)
  111.     {
  112.         $map = array('objectclasses'     => &$this->_objectClasses,
  113.                      'attributes'        => &$this->_attributeTypes,
  114.                      'ditcontentrules'   => &$this->_dITContentRules,
  115.                      'ditstructurerules' => &$this->_dITStructureRules,
  116.                      'matchingrules'     => &$this->_matchingRules,
  117.                      'matchingruleuses'  => &$this->_matchingRuleUse,
  118.                      'nameforms'         => &$this->_nameForms,
  119.                      'syntaxes'          => &$this->_ldapSyntaxes );
  120.  
  121.         $key strtolower($type);
  122.         $ret ((key_exists($key$map)) $map[$key: PEAR::raiseError("Unknown type $type"));
  123.         return $ret;
  124.     }
  125.  
  126.     /**
  127.     * Return a specific entry
  128.     *
  129.     * @param string $type Type of name
  130.     * @param string $name Name or OID to fetch
  131.     *
  132.     * @access public
  133.     * @return mixed Entry or Net_LDAP_Error
  134.     */
  135.     function &get($type$name)
  136.     {
  137.         if ($this->_initialized{
  138.             $type strtolower($type);
  139.             if (false == key_exists($type$this->types)) {
  140.                 return PEAR::raiseError("No such type $type");
  141.             }
  142.  
  143.             $name     strtolower($name);
  144.             $type_var &$this->{'_' $this->types[$type]};
  145.  
  146.             if (key_exists($name$type_var)) {
  147.                 return $type_var[$name];
  148.             elseif (key_exists($name$this->_oids&& $this->_oids[$name]['type'== $type{
  149.                 return $this->_oids[$name];
  150.             else {
  151.                 return PEAR::raiseError("Could not find $type $name");
  152.             }
  153.         else {
  154.             $return = null;
  155.             return $return;
  156.         }
  157.     }
  158.  
  159.  
  160.     /**
  161.     * Fetches attributes that MAY be present in the given objectclass
  162.     *
  163.     * @param string $oc Name or OID of objectclass
  164.     *
  165.     * @access public
  166.     * @return array|Net_LDAP_ErrorArray with attributes or Net_LDAP_Error
  167.     */
  168.     function may($oc)
  169.     {
  170.         return $this->_getAttr($oc'may');
  171.     }
  172.  
  173.     /**
  174.     * Fetches attributes that MUST be present in the given objectclass
  175.     *
  176.     * @param string $oc Name or OID of objectclass
  177.     *
  178.     * @access public
  179.     * @return array|Net_LDAP_ErrorArray with attributes or Net_LDAP_Error
  180.     */
  181.     function must($oc)
  182.     {
  183.         return $this->_getAttr($oc'must');
  184.     }
  185.  
  186.     /**
  187.     * Fetches the given attribute from the given objectclass
  188.     *
  189.     * @param string $oc   Name or OID of objectclass
  190.     * @param string $attr Name of attribute to fetch
  191.     *
  192.     * @access private
  193.     * @return array|Net_LDAP_ErrorThe attribute or Net_LDAP_Error
  194.     */
  195.     function _getAttr($oc$attr)
  196.     {
  197.         $oc strtolower($oc);
  198.         if (key_exists($oc$this->_objectClasses&& key_exists($attr$this->_objectClasses[$oc])) {
  199.             return $this->_objectClasses[$oc][$attr];
  200.         elseif (key_exists($oc$this->_oids&&
  201.                 $this->_oids[$oc]['type'== 'objectclass' &&
  202.                 key_exists($attr$this->_oids[$oc])) {
  203.             return $this->_oids[$oc][$attr];
  204.         else {
  205.             return PEAR::raiseError("Could not find $attr attributes for $oc ");
  206.         }
  207.     }
  208.  
  209.     /**
  210.     * Returns the name(s) of the immediate superclass(es)
  211.     *
  212.     * @param string $oc Name or OID of objectclass
  213.     *
  214.     * @return array|Net_LDAP_Error Array of names or Net_LDAP_Error
  215.     */
  216.     function superclass($oc)
  217.     {
  218.         $o $this->get('objectclass'$oc);
  219.         if (Net_LDAP::isError($o)) {
  220.             return $o;
  221.         }
  222.         return (key_exists('sup'$o$o['sup': array());
  223.     }
  224.  
  225.     /**
  226.     * Parses the schema of the given Subschema entry
  227.     *
  228.     * @param Net_LDAP_Entry &$entry Subschema entry
  229.     *
  230.     * @access public
  231.     */
  232.     function parse(&$entry)
  233.     {
  234.         foreach ($this->types as $type => $attr{
  235.             // initialize map type to entry
  236.             $type_var          '_' $attr;
  237.             $this->{$type_var= array();
  238.  
  239.             // get values for this type
  240.             if ($entry->exists($attr)) {
  241.                 $values $entry->getValue($attr);
  242.                 if (is_array($values)) {
  243.                     foreach ($values as $value{
  244.  
  245.                         unset($schema_entry)// this was a real mess without it
  246.  
  247.                         // get the schema entry
  248.                         $schema_entry $this->_parse_entry($value);
  249.  
  250.                         // set the type
  251.                         $schema_entry['type'$type;
  252.  
  253.                         // save a ref in $_oids
  254.                         $this->_oids[$schema_entry['oid']] &$schema_entry;
  255.  
  256.                         // save refs for all names in type map
  257.                         $names $schema_entry['aliases'];
  258.                         array_push($names$schema_entry['name']);
  259.                         foreach ($names as $name{
  260.                             $this->{$type_var}[strtolower($name)&$schema_entry;
  261.                         }
  262.                     }
  263.                 }
  264.             }
  265.         }
  266.         $this->_initialized = true;
  267.     }
  268.  
  269.     /**
  270.     * parses an attribute value into a schema entry
  271.     *
  272.     * @param string $value Attribute value
  273.     *
  274.     * @access private
  275.     * @return array|falseSchema entry array or false
  276.     */
  277.     function &_parse_entry($value)
  278.     {
  279.         // tokens that have no value associated
  280.         $noValue = array('single-value',
  281.                          'obsolete',
  282.                          'collective',
  283.                          'no-user-modification',
  284.                          'abstract',
  285.                          'structural',
  286.                          'auxiliary');
  287.  
  288.         // tokens that can have multiple values
  289.         $multiValue = array('must''may''sup');
  290.  
  291.         $schema_entry = array('aliases' => array())// initilization
  292.  
  293.         $tokens $this->_tokenize($value)// get an array of tokens
  294.  
  295.         // remove surrounding brackets
  296.         if ($tokens[0== '('array_shift($tokens);
  297.         if ($tokens[count($tokens- 1== ')'array_pop($tokens)// -1 doesnt work on arrays :-(
  298.  
  299.         $schema_entry['oid'array_shift($tokens)// first token is the oid
  300.  
  301.         // cycle over the tokens until none are left
  302.         while (count($tokens> 0{
  303.             $token strtolower(array_shift($tokens));
  304.             if (in_array($token$noValue)) {
  305.                 $schema_entry[$token= 1; // single value token
  306.             else {
  307.                 // this one follows a string or a list if it is multivalued
  308.                 if (($schema_entry[$tokenarray_shift($tokens)) == '('{
  309.                     // this creates the list of values and cycles through the tokens
  310.                     // until the end of the list is reached ')'
  311.                     $schema_entry[$token= array();
  312.                     while ($tmp array_shift($tokens)) {
  313.                         if ($tmp == ')'break;
  314.                         if ($tmp != '$'array_push($schema_entry[$token]$tmp);
  315.                     }
  316.                 }
  317.                 // create a array if the value should be multivalued but was not
  318.                 if (in_array($token$multiValue&& !is_array($schema_entry[$token])) {
  319.                     $schema_entry[$token= array($schema_entry[$token]);
  320.                 }
  321.             }
  322.         }
  323.         // get max length from syntax
  324.         if (key_exists('syntax'$schema_entry)) {
  325.             if (preg_match('/{(\d+)}/'$schema_entry['syntax']$matches)) {
  326.                 $schema_entry['max_length'$matches[1];
  327.             }
  328.         }
  329.         // force a name
  330.         if (empty($schema_entry['name'])) {
  331.             $schema_entry['name'$schema_entry['oid'];
  332.         }
  333.         // make one name the default and put the other ones into aliases
  334.         if (is_array($schema_entry['name'])) {
  335.             $aliases                 $schema_entry['name'];
  336.             $schema_entry['name']    array_shift($aliases);
  337.             $schema_entry['aliases'$aliases;
  338.         }
  339.         return $schema_entry;
  340.     }
  341.  
  342.     /**
  343.     * tokenizes the given value into an array of tokens
  344.     *
  345.     * @param string $value String to parse
  346.     *
  347.     * @access private
  348.     * @return array Array of tokens
  349.     */
  350.     function _tokenize($value)
  351.     {
  352.         $tokens  = array();       // array of tokens
  353.         $matches = array();       // matches[0] full pattern match, [1,2,3] subpatterns
  354.  
  355.         // this one is taken from perl-ldap, modified for php
  356.         $pattern "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x";
  357.  
  358.         /**
  359.          * This one matches one big pattern wherin only one of the three subpatterns matched
  360.          * We are interested in the subpatterns that matched. If it matched its value will be
  361.          * non-empty and so it is a token. Tokens may be round brackets, a string, or a string
  362.          * enclosed by '
  363.          */
  364.         preg_match_all($pattern$value$matches);
  365.  
  366.         for ($i = 0; $i count($matches[0])$i++{     // number of tokens (full pattern match)
  367.             for ($j = 1; $j < 4; $j++{                  // each subpattern
  368.                 if (null != trim($matches[$j][$i])) {     // pattern match in this subpattern
  369.                     $tokens[$itrim($matches[$j][$i])// this is the token
  370.                 }
  371.             }
  372.         }
  373.         return $tokens;
  374.     }
  375.  
  376.     /**
  377.     * Returns wether a attribute syntax is binary or not
  378.     *
  379.     * This method gets used by Net_LDAP_Entry to decide which
  380.     * PHP function needs to be used to fetch the value in the
  381.     * proper format (e.g. binary or string)
  382.     *
  383.     * @param string $attribute The name of the attribute (eg.: 'sn')
  384.     *
  385.     * @access public
  386.     * @return boolean 
  387.     */
  388.     function isBinary($attribute)
  389.     {
  390.         $return = false; // default to false
  391.  
  392.         // This list contains all syntax that should be treaten as
  393.         // containing binary values
  394.         // The Syntax Definitons go into constants at the top of this page
  395.         $syntax_binary = array(
  396.                            NET_LDAP_SYNTAX_OCTET_STRING,
  397.                            NET_LDAP_SYNTAX_JPEG
  398.                          );
  399.  
  400.         // Check Syntax
  401.         $attr_s $this->get('attribute'$attribute);
  402.         if (Net_LDAP::isError($attr_s)) {
  403.             // Attribute not found in schema
  404.             $return = false; // consider attr not binary
  405.         elseif (isset($attr_s['syntax']&& in_array($attr_s['syntax']$syntax_binary)) {
  406.             // Syntax is defined as binary in schema
  407.             $return = true;
  408.         else {
  409.             // Syntax not defined as binary, or not found
  410.             // if attribute is a subtype, check superior attribute syntaxes
  411.             if (isset($attr_s['sup'])) {
  412.                 foreach ($attr_s['sup'as $superattr{
  413.                     $return $this->isBinary($superattr);
  414.                     if ($return{
  415.                         break; // stop checking parents since we are binary
  416.                     }
  417.                 }
  418.             }
  419.         }
  420.  
  421.         return $return;
  422.     }
  423. }
  424. ?>

Documentation generated on Mon, 11 Mar 2019 15:22:34 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.