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

Source for file Entry.php

Documentation is available at Entry.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3.  
  4. require_once 'PEAR.php';
  5. require_once 'Util.php';
  6.  
  7. /**
  8. * Object representation of a directory entry
  9. *
  10. * This class represents a directory entry. You can add, delete, replace
  11. * attributes and their values, rename the entry, delete the entry.
  12. *
  13. @category Net
  14. @package  Net_LDAP2
  15. @author   Jan Wagner <wagner@netsols.de>
  16. @author   Tarjej Huse <tarjei@bergfald.no>
  17. @license  http://www.gnu.org/copyleft/lesser.html LGPL
  18. @version  CVS: $Id: Entry.php,v 1.9 2008/11/03 14:07:29 beni Exp $
  19. @link     http://pear.php.net/package/Net_LDAP22/
  20.  
  21. */
  22. class Net_LDAP2_Entry extends PEAR
  23. {
  24.     /**
  25.     * Entry ressource identifier
  26.     *
  27.     * @access protected
  28.     * @var ressource 
  29.     */
  30.     protected $_entry = null;
  31.  
  32.     /**
  33.     * LDAP ressource identifier
  34.     *
  35.     * @access protected
  36.     * @var ressource 
  37.     */
  38.     protected $_link = null;
  39.  
  40.     /**
  41.     * Net_LDAP2 object
  42.     *
  43.     * This object will be used for updating and schema checking
  44.     *
  45.     * @access protected
  46.     * @var object Net_LDAP2 
  47.     */
  48.     protected $_ldap = null;
  49.  
  50.     /**
  51.     * Distinguished name of the entry
  52.     *
  53.     * @access protected
  54.     * @var string 
  55.     */
  56.     protected $_dn = null;
  57.  
  58.     /**
  59.     * Attributes
  60.     *
  61.     * @access protected
  62.     * @var array 
  63.     */
  64.     protected $_attributes = array();
  65.  
  66.     /**
  67.     * Original attributes before any modification
  68.     *
  69.     * @access protected
  70.     * @var array 
  71.     */
  72.     protected $_original = array();
  73.  
  74.  
  75.     /**
  76.     * Map of attribute names
  77.     *
  78.     * @access protected
  79.     * @var array 
  80.     */
  81.     protected $_map = array();
  82.  
  83.  
  84.     /**
  85.     * Is this a new entry?
  86.     *
  87.     * @access protected
  88.     * @var boolean 
  89.     */
  90.     protected $_new = true;
  91.  
  92.     /**
  93.     * New distinguished name
  94.     *
  95.     * @access protected
  96.     * @var string 
  97.     */
  98.     protected $_newdn = null;
  99.  
  100.     /**
  101.     * Shall the entry be deleted?
  102.     *
  103.     * @access protected
  104.     * @var boolean 
  105.     */
  106.     protected $_delete = false;
  107.  
  108.     /**
  109.     * Map with changes to the entry
  110.     *
  111.     * @access protected
  112.     * @var array 
  113.     */
  114.     protected $_changes = array("add"     => array(),
  115.                                 "delete"  => array(),
  116.                                 "replace" => array()
  117.                                );
  118.     /**
  119.     * Internal Constructor
  120.     *
  121.     * Constructor of the entry. Sets up the distinguished name and the entries
  122.     * attributes.
  123.     * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()}
  124.     * or {@link Net_LDAP2_Entry::createConnected()} instead!
  125.     *
  126.     * @param Net_LDAP2|ressource|array&$ldap Net_LDAP2 object, ldap-link ressource or array of attributes
  127.     * @param string|ressource        $entry Either a DN or a LDAP-Entry ressource
  128.     *
  129.     * @access protected
  130.     * @return none 
  131.     */
  132.     protected function __construct(&$ldap$entry = null)
  133.     {
  134.         $this->PEAR('Net_LDAP2_Error');
  135.  
  136.         // set up entry resource or DN
  137.         if (is_resource($entry)) {
  138.             $this->_entry = &$entry;
  139.         else {
  140.             $this->_dn = $entry;
  141.         }
  142.  
  143.         // set up LDAP link
  144.         if ($ldap instanceof Net_LDAP2{
  145.             $this->_ldap = &$ldap;
  146.             $this->_link = $ldap->getLink();
  147.         elseif (is_resource($ldap)) {
  148.             $this->_link = $ldap;
  149.         elseif (is_array($ldap)) {
  150.             // Special case: here $ldap is an array of attributes,
  151.             // this means, we have no link. This is a "virtual" entry.
  152.             // We just set up the attributes so one can work with the object
  153.             // as expected, but an update() fails unless setLDAP() is called.
  154.             $this->_setAttributes($ldap);
  155.         }
  156.  
  157.         // if this is an entry existing in the directory,
  158.         // then set up as old and fetch attrs
  159.         if (is_resource($this->_entry&& is_resource($this->_link)) {
  160.             $this->_new = false;
  161.             $this->_dn  = @ldap_get_dn($this->_link$this->_entry);
  162.             $this->_setAttributes();  // fetch attributes from server
  163.         }
  164.     }
  165.  
  166.     /**
  167.     * Creates a fresh entry that may be added to the directory later on
  168.     *
  169.     * Use this method, if you want to initialize a fresh entry.
  170.     *
  171.     * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh();
  172.     * You should put a 'objectClass' attribute into the $attrs so the directory server
  173.     * knows which object you want to create. However, you may omit this in case you
  174.     * don't want to add this entry to a directory server.
  175.     *
  176.     * The attributes parameter is as following:
  177.     * <code>
  178.     * $attrs = array( 'attribute1' => array('value1', 'value2'),
  179.     *                 'attribute2' => 'single value'
  180.     *          );
  181.     * </code>
  182.     *
  183.     * @param string $dn    DN of the Entry
  184.     * @param array  $attrs Attributes of the entry
  185.     *
  186.     * @static
  187.     * @return Net_LDAP2_Entry|Net_LDAP2_Error
  188.     */
  189.     public static function createFresh($dn$attrs = array())
  190.     {
  191.         if (!is_array($attrs)) {
  192.             return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!");
  193.         }
  194.  
  195.         $entry = new Net_LDAP2_Entry($attrs$dn);
  196.         return $entry;
  197.     }
  198.  
  199.     /**
  200.     * Creates a Net_LDAP2_Entry object out of an ldap entry resource
  201.     *
  202.     * Use this method, if you want to initialize an entry object that is
  203.     * already present in some directory and that you have read manually.
  204.     *
  205.     * Please note, that if you want to create an entry object that represents
  206.     * some already existing entry, you should use {@link createExisting()}.
  207.     *
  208.     * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected();
  209.     *
  210.     * @param Net_LDAP2 $ldap Net_LDA2 object
  211.     * @param resource  $entry PHP LDAP entry resource
  212.     *
  213.     * @static
  214.     * @return Net_LDAP2_Entry|Net_LDAP2_Error
  215.     */
  216.     public static function createConnected(&$ldap$entry)
  217.     {
  218.         if (!$ldap instanceof Net_LDAP2{
  219.             return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!");
  220.         }
  221.         if (!is_resource($entry)) {
  222.             return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!");
  223.         }
  224.  
  225.         $entry = new Net_LDAP2_Entry($ldap$entry);
  226.         return $entry;
  227.     }
  228.  
  229.     /**
  230.     * Creates an Net_LDAP2_Entry object that is considered already existing
  231.     *
  232.     * Use this method, if you want to modify an already existing entry
  233.     * without fetching it first.
  234.     * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()!
  235.     *
  236.     * Please note that you should take care if you construct entries manually with this
  237.     * because you may get weird synchronisation problems.
  238.     * The attributes and values as well as the entry itself are considered existent
  239.     * which may produce errors if you try to modify an entry which doesn't really exist
  240.     * or if you try to overwrite some attribute with an value already present.
  241.     *
  242.     * This method is equal to calling createFresh() and after that markAsNew(FALSE).
  243.     *
  244.     * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting();
  245.     *
  246.     * The attributes parameter is as following:
  247.     * <code>
  248.     * $attrs = array( 'attribute1' => array('value1', 'value2'),
  249.     *                 'attribute2' => 'single value'
  250.     *          );
  251.     * </code>
  252.     *
  253.     * @param string    $dn    DN of the Entry
  254.     * @param array     $attrs Attributes of the entry
  255.     *
  256.     * @static
  257.     * @return Net_LDAP2_Entry|Net_LDAP2_Error
  258.     */
  259.     public static function createExisting($dn$attrs = array())
  260.     {
  261.         if (!is_array($attrs)) {
  262.             return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!");
  263.         }
  264.  
  265.         $entry Net_LDAP2_Entry::createFresh($attrs$dn);
  266.         if ($entry instanceof Net_LDAP2_Error{
  267.             return $entry;
  268.         else {
  269.             $entry->markAsNew(FALSE);
  270.             return $entry;
  271.         }
  272.     }
  273.  
  274.     /**
  275.     * Get or set the distinguished name of the entry
  276.     *
  277.     * If called without an argument the current (or the new DN if set) DN gets returned.
  278.     * If you provide an DN, this entry is moved to the new location specified if a DN existed.
  279.     * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create
  280.     * the new Entry in the directory.
  281.     * To fetch the current active DN after setting a new DN but before an update(), you can use
  282.     * {@link currentDN()} to retrieve the DN that is currently active.
  283.     *
  284.     * Please note that special characters (eg german umlauts) should be encoded using utf8_encode().
  285.     * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN.
  286.     *
  287.     * @param string $dn New distinguished name
  288.     *
  289.     * @access public
  290.     * @return string|trueDistinguished name (or true if a new DN was provided)
  291.     */
  292.     public function dn($dn = null)
  293.     {
  294.         if (false == is_null($dn)) {
  295.             if (is_null($this->_dn)) {
  296.                 $this->_dn = $dn;
  297.             else {
  298.                 $this->_newdn = $dn;
  299.             }
  300.             return true;
  301.         }
  302.         return (isset($this->_newdn$this->_newdn : $this->currentDN());
  303.     }
  304.  
  305.     /**
  306.     * Renames or moves the entry
  307.     *
  308.     * This is just a convinience alias to {@link dn()}
  309.     * to make your code more meaningful.
  310.     *
  311.     * @param string $newdn The new DN
  312.     * @return true 
  313.     */
  314.     public function move($newdn)
  315.     {
  316.         return $this->dn($newdn);
  317.     }
  318.  
  319.     /**
  320.     * Sets the internal attributes array
  321.     *
  322.     * This fetches the values for the attributes from the server.
  323.     * The attribute Syntax will be checked so binary attributes will be returned
  324.     * as binary values.
  325.     *
  326.     * Attributes may be passed directly via the $attributes parameter to setup this
  327.     * entry manually. This overrides attribute fetching from the server.
  328.     *
  329.     * @param array $attributes Attributes to set for this entry
  330.     *
  331.     * @access protected
  332.     * @return void 
  333.     */
  334.     protected function _setAttributes($attributes = null)
  335.     {
  336.         /*
  337.         * fetch attributes from the server
  338.         */
  339.         if (is_null($attributes&& is_resource($this->_entry&& is_resource($this->_link)) {
  340.             // fetch schema
  341.             if ($this->_ldap instanceof Net_LDAP2{
  342.                 $schema =$this->_ldap->schema();
  343.             }
  344.             // fetch attributes
  345.             $attributes = array();
  346.             do {
  347.                 if (empty($attr)) {
  348.                     $ber  = null;
  349.                     $attr @ldap_first_attribute($this->_link$this->_entry$ber);
  350.                 else {
  351.                     $attr @ldap_next_attribute($this->_link$this->_entry$ber);
  352.                 }
  353.                 if ($attr{
  354.                     $func 'ldap_get_values'// standard function to fetch value
  355.  
  356.                     // Try to get binary values as binary data
  357.                     if ($schema instanceof Net_LDAP2_Schema{
  358.                         if ($schema->isBinary($attr)) {
  359.                              $func 'ldap_get_values_len';
  360.                         }
  361.                     }
  362.                     // fetch attribute value (needs error checking?)
  363.                     $attributes[$attr$func($this->_link$this->_entry$attr);
  364.                 }
  365.             while ($attr);
  366.         }
  367.  
  368.         /*
  369.         * set attribute data directly, if passed
  370.         */
  371.         if (is_array($attributes&& count($attributes> 0{
  372.             if (isset($attributes["count"]&& is_numeric($attributes["count"])) {
  373.                 unset($attributes["count"]);
  374.             }
  375.             foreach ($attributes as $k => $v{
  376.                 // attribute names should not be numeric
  377.                 if (is_numeric($k)) {
  378.                     continue;
  379.                 }
  380.                 // map generic attribute name to real one
  381.                 $this->_map[strtolower($k)$k;
  382.                 // attribute values should be in an array
  383.                 if (false == is_array($v)) {
  384.                     $v = array($v);
  385.                 }
  386.                 // remove the value count (comes from ldap server)
  387.                 if (isset($v["count"])) {
  388.                     unset($v["count"]);
  389.                 }
  390.                 $this->_attributes[$k$v;
  391.             }
  392.         }
  393.  
  394.         // save a copy for later use
  395.         $this->_original = $this->_attributes;
  396.     }
  397.  
  398.     /**
  399.     * Get the values of all attributes in a hash
  400.     *
  401.     * The returned hash has the form
  402.     * <code>array('attributename' => 'single value',
  403.     *       'attributename' => array('value1', value2', value3'))</code>
  404.     *
  405.     * @access public
  406.     * @return array Hash of all attributes with their values
  407.     */
  408.     public function getValues()
  409.     {
  410.         $attrs = array();
  411.         foreach ($this->_attributes as $attr => $value{
  412.             $attrs[$attr$this->getValue($attr);
  413.         }
  414.         return $attrs;
  415.     }
  416.  
  417.     /**
  418.     * Get the value of a specific attribute
  419.     *
  420.     * The first parameter is the name of the attribute
  421.     * The second parameter influences the way the value is returned:
  422.     * 'single': only the first value is returned as string
  423.     * 'all': all values including the value count are returned in an
  424.     *               array
  425.     * 'default': in all other cases an attribute value with a single value is
  426.     *            returned as string, if it has multiple values it is returned
  427.     *            as an array (without value count)
  428.     *
  429.     * @param string $attr   Attribute name
  430.     * @param string $option Option
  431.     *
  432.     * @access public
  433.     * @return string|array|PEAR_Errorstring, array or PEAR_Error
  434.     */
  435.     public function getValue($attr$option = null)
  436.     {
  437.         $attr $this->_getAttrName($attr);
  438.  
  439.         if (false == array_key_exists($attr$this->_attributes)) {
  440.             return PEAR::raiseError("Unknown attribute ($attr) requested");
  441.         }
  442.  
  443.         $value $this->_attributes[$attr];
  444.  
  445.         if ($option == "single" || (count($value== 1 && $option != 'all')) {
  446.             $value array_shift($value);
  447.         }
  448.  
  449.         return $value;
  450.     }
  451.  
  452.     /**
  453.     * Alias function of getValue for perl-ldap interface
  454.     *
  455.     * @see getValue()
  456.     * @return string|array|PEAR_Error
  457.     */
  458.     public function get_value()
  459.     {
  460.         $args func_get_args();
  461.         return call_user_func_array(array&$this'getValue' )$args);
  462.     }
  463.  
  464.     /**
  465.     * Returns an array of attributes names
  466.     *
  467.     * @access public
  468.     * @return array Array of attribute names
  469.     */
  470.     public function attributes()
  471.     {
  472.         return array_keys($this->_attributes);
  473.     }
  474.  
  475.     /**
  476.     * Returns whether an attribute exists or not
  477.     *
  478.     * @param string $attr Attribute name
  479.     *
  480.     * @access public
  481.     * @return boolean 
  482.     */
  483.     public function exists($attr)
  484.     {
  485.         $attr $this->_getAttrName($attr);
  486.         return array_key_exists($attr$this->_attributes);
  487.     }
  488.  
  489.     /**
  490.     * Adds a new attribute or a new value to an existing attribute
  491.     *
  492.     * The paramter has to be an array of the form:
  493.     * array('attributename' => 'single value',
  494.     *       'attributename' => array('value1', 'value2))
  495.     * When the attribute already exists the values will be added, else the
  496.     * attribute will be created. These changes are local to the entry and do
  497.     * not affect the entry on the server until update() is called.
  498.     *
  499.     * Note, that you can add values of attributes that you haven't selected, but if
  500.     * you do so, {@link getValue()} and {@link getValues()} will only return the
  501.     * values you added, _NOT_ all values present on the server. To avoid this, just refetch
  502.     * the entry after calling {@link update()} or select the attribute.
  503.     *
  504.     * @param array $attr Attributes to add
  505.     *
  506.     * @access public
  507.     * @return true|Net_LDAP2_Error
  508.     */
  509.     public function add($attr = array())
  510.     {
  511.         if (false == is_array($attr)) {
  512.             return PEAR::raiseError("Parameter must be an array");
  513.         }
  514.         foreach ($attr as $k => $v{
  515.             $k $this->_getAttrName($k);
  516.             if (false == is_array($v)) {
  517.                 // Do not add empty values
  518.                 if ($v == null{
  519.                     continue;
  520.                 else {
  521.                     $v = array($v);
  522.                 }
  523.             }
  524.             // add new values to existing attribute or add new attribute
  525.             if ($this->exists($k)) {
  526.                 $this->_attributes[$karray_unique(array_merge($this->_attributes[$k]$v));
  527.             else {
  528.                 $this->_map[strtolower($k)$k;
  529.                 $this->_attributes[$k]      $v;
  530.             }
  531.             // save changes for update()
  532.             if (empty($this->_changes["add"][$k])) {
  533.                 $this->_changes["add"][$k= array();
  534.             }
  535.             $this->_changes["add"][$karray_unique(array_merge($this->_changes["add"][$k]$v));
  536.         }
  537.         $return = true;
  538.         return $return;
  539.     }
  540.  
  541.     /**
  542.     * Deletes an whole attribute or a value or the whole entry
  543.     *
  544.     * The parameter can be one of the following:
  545.     *
  546.     * "attributename" - The attribute as a whole will be deleted
  547.     * array("attributename1", "attributename2) - All given attributes will be
  548.     *                                            deleted
  549.     * array("attributename" => "value") - The value will be deleted
  550.     * array("attributename" => array("value1", "value2") - The given values
  551.     *                                                      will be deleted
  552.     * If $attr is null or omitted , then the whole Entry will be deleted!
  553.     *
  554.     * These changes are local to the entry and do
  555.     * not affect the entry on the server until {@link update()} is called.
  556.     *
  557.     * Please note that you must select the attribute (at $ldap->search() for example)
  558.     * to be able to delete values of it, Otherwise {@link update()} will silently fail
  559.     * and remove nothing.
  560.     *
  561.     * @param string|array$attr Attributes to delete (NULL or missing to delete whole entry)
  562.     *
  563.     * @access public
  564.     * @return true 
  565.     */
  566.     public function delete($attr = null)
  567.     {
  568.         if (is_null($attr)) {
  569.             $this->_delete = true;
  570.             return true;
  571.         }
  572.         if (is_string($attr)) {
  573.             $attr = array($attr);
  574.         }
  575.         // Make the assumption that attribute names cannot be numeric,
  576.         // therefore this has to be a simple list of attribute names to delete
  577.         if (is_numeric(key($attr))) {
  578.             foreach ($attr as $name{
  579.                 if (is_array($name)) {
  580.                     // someone mixed modes (list mode but specific values given!)
  581.                     $del_attr_name array_search($name$attr);
  582.                     $this->delete(array($del_attr_name => $name));
  583.                 else {
  584.                     // mark for update() if this attr was not marked before
  585.                     $name $this->_getAttrName($name);
  586.                     if ($this->exists($name)) {
  587.                         $this->_changes["delete"][$name= null;
  588.                         unset($this->_attributes[$name]);
  589.                     }
  590.                 }
  591.             }
  592.         else {
  593.             // Here we have a hash with "attributename" => "value to delete"
  594.             foreach ($attr as $name => $values{
  595.                 if (is_int($name)) {
  596.                     // someone mixed modes and gave us just an attribute name
  597.                     $this->delete($values);
  598.                 else {
  599.                     // mark for update() if this attr was not marked before;
  600.                     // this time it must consider the selected values also
  601.                     $name $this->_getAttrName($name);
  602.                     if ($this->exists($name)) {
  603.                         if (false == is_array($values)) {
  604.                             $values = array($values);
  605.                         }
  606.                         // save values to be deleted
  607.                         if (empty($this->_changes["delete"][$name])) {
  608.                             $this->_changes["delete"][$name= array();
  609.                         }
  610.                         $this->_changes["delete"][$name=
  611.                             array_unique(array_merge($this->_changes["delete"][$name]$values));
  612.                         foreach ($values as $value{
  613.                             // find the key for the value that should be deleted
  614.                             $key array_search($value$this->_attributes[$name]);
  615.                             if (false !== $key{
  616.                                 // delete the value
  617.                                 unset($this->_attributes[$name][$key]);
  618.                             }
  619.                         }
  620.                     }
  621.                 }
  622.             }
  623.         }
  624.         $return = true;
  625.         return $return;
  626.     }
  627.  
  628.     /**
  629.     * Replaces attributes or its values
  630.     *
  631.     * The parameter has to an array of the following form:
  632.     * array("attributename" => "single value",
  633.     *       "attribute2name" => array("value1", "value2"))
  634.     * If the attribute does not yet exist it will be added instead (see also $force).
  635.     * If the attribue value is null, the attribute will de deleted.
  636.     *
  637.     * These changes are local to the entry and do
  638.     * not affect the entry on the server until {@link update()} is called.
  639.     *
  640.     * In some cases you are not allowed to read the attributes value (for
  641.     * example the ActiveDirectory attribute unicodePwd) but are allowed to
  642.     * replace the value. In this case replace() would assume that the attribute
  643.     * is not in the directory yet and tries to add it which will result in an
  644.     * LDAP_TYPE_OR_VALUE_EXISTS error.
  645.     * To force replace mode instead of add, you can set $force to true.
  646.     *
  647.     * @param array $attr  Attributes to replace
  648.     * @param bool  $force Force replacing mode in case we can't read the attr value but are allowed to replace it
  649.     *
  650.     * @access public
  651.     * @return true|Net_LDAP2_Error
  652.     */
  653.     public function replace($attr = array()$force = false)
  654.     {
  655.         if (false == is_array($attr)) {
  656.             return PEAR::raiseError("Parameter must be an array");
  657.         }
  658.         foreach ($attr as $k => $v{
  659.             $k $this->_getAttrName($k);
  660.             if (false == is_array($v)) {
  661.                 // delete attributes with empty values
  662.                 if ($v == null{
  663.                     $this->delete($k);
  664.                     continue;
  665.                 else {
  666.                     $v = array($v);
  667.                 }
  668.             }
  669.             // existing attributes will get replaced
  670.             if ($this->exists($k|| $force{
  671.                 $this->_changes["replace"][$k$v;
  672.                 $this->_attributes[$k]         $v;
  673.             else {
  674.                 // new ones just get added
  675.                 $this->add(array($k => $v));
  676.             }
  677.         }
  678.         $return = true;
  679.         return $return;
  680.     }
  681.  
  682.     /**
  683.     * Update the entry on the directory server
  684.     *
  685.     * This will evaluate all changes made so far and send them
  686.     * to the directory server.
  687.     * Please note, that if you make changes to objectclasses wich
  688.     * have mandatory attributes set, update() will currently fail.
  689.     * Remove the entry from the server and readd it as new in such cases.
  690.     * This also will deal with problems with setting structural object classes.
  691.     *
  692.     * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance
  693.     *
  694.     * @access public
  695.     * @return true|Net_LDAP2_Error
  696.     * @todo Entry rename with a DN containing special characters needs testing!
  697.     */
  698.     public function update($ldap = null)
  699.     {
  700.         if ($ldap{
  701.             $msg $this->setLDAP($ldap);
  702.             if (Net_LDAP2::isError($msg)) {
  703.                 return PEAR::raiseError('You passed an invalid $ldap variable to update()');
  704.             }
  705.         }
  706.  
  707.         // ensure we have a valid LDAP object
  708.         $ldap =$this->getLDAP();
  709.         if (!$ldap instanceof Net_LDAP2{
  710.             return PEAR::raiseError("The entries LDAP object is not valid");
  711.         }
  712.  
  713.         // Get and check link
  714.         $link $ldap->getLink();
  715.         if (!is_resource($link)) {
  716.             return PEAR::raiseError("Could not update entry: internal LDAP link is invalid");
  717.         }
  718.  
  719.         /*
  720.         * Delete the entry
  721.         */
  722.         if (true === $this->_delete{
  723.             return $ldap->delete($this);
  724.         }
  725.  
  726.         /*
  727.         * New entry
  728.         */
  729.         if (true === $this->_new{
  730.             $msg $ldap->add($this);
  731.             if (Net_LDAP2::isError($msg)) {
  732.                 return $msg;
  733.             }
  734.             $this->_new                = false;
  735.             $this->_changes['add']     = array();
  736.             $this->_changes['delete']  = array();
  737.             $this->_changes['replace'= array();
  738.             $this->_original           = $this->_attributes;
  739.  
  740.             $return = true;
  741.             return $return;
  742.         }
  743.  
  744.         /*
  745.         * Rename/move entry
  746.         */
  747.         if (false == is_null($this->_newdn)) {
  748.             if ($ldap->getLDAPVersion(!== 3{
  749.                 return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3");
  750.             }
  751.             // make dn relative to parent (needed for ldap rename)
  752.             $parent Net_LDAP2_Util::ldap_explode_dn($this->_newdnarray('casefolding' => 'none''reverse' => false'onlyvalues' => false));
  753.             if (Net_LDAP2::isError($parent)) {
  754.                 return $parent;
  755.             }
  756.             $child array_shift($parent);
  757.             // maybe the dn consist of a multivalued RDN, we must build the dn in this case
  758.             // because the $child-RDN is an array!
  759.             if (is_array($child)) {
  760.                 $child Net_LDAP2_Util::canonical_dn($child);
  761.             }
  762.             $parent Net_LDAP2_Util::canonical_dn($parent);
  763.  
  764.             // rename/move
  765.             if (false == @ldap_rename($link$this->_dn$child$parenttrue)) {
  766.                 return PEAR::raiseError("Entry not renamed: " .
  767.                                         @ldap_error($link)@ldap_errno($link));
  768.             }
  769.             // reflect changes to local copy
  770.             $this->_dn    = $this->_newdn;
  771.             $this->_newdn = null;
  772.         }
  773.  
  774.         /*
  775.         * Carry out modifications to the entry
  776.         */
  777.         // ADD
  778.         foreach ($this->_changes["add"as $attr => $value{
  779.             // if attribute exists, add new values
  780.             if ($this->exists($attr)) {
  781.                 if (false === @ldap_mod_add($link$this->dn()array($attr => $value))) {
  782.                     return PEAR::raiseError("Could not add new values to attribute $attr" .
  783.                                             @ldap_error($link)@ldap_errno($link));
  784.                 }
  785.             else {
  786.                 // new attribute
  787.                 if (false === @ldap_modify($link$this->dn()array($attr => $value))) {
  788.                     return PEAR::raiseError("Could not add new attribute $attr" .
  789.                                             @ldap_error($link)@ldap_errno($link));
  790.                 }
  791.             }
  792.             // all went well here, I guess
  793.             unset($this->_changes["add"][$attr]);
  794.         }
  795.  
  796.         // DELETE
  797.         foreach ($this->_changes["delete"as $attr => $value{
  798.             // In LDAPv3 you need to specify the old values for deleting
  799.             if (is_null($value&& $ldap->getLDAPVersion(=== 3{
  800.                 $value $this->_original[$attr];
  801.             }
  802.             if (false === @ldap_mod_del($link$this->dn()array($attr => $value))) {
  803.                 return PEAR::raiseError("Could not delete attribute $attr" .
  804.                                         @ldap_error($link)@ldap_errno($link));
  805.             }
  806.             unset($this->_changes["delete"][$attr]);
  807.         }
  808.  
  809.         // REPLACE
  810.         foreach ($this->_changes["replace"as $attr => $value{
  811.             if (false === @ldap_modify($link$this->dn()array($attr => $value))) {
  812.                 return PEAR::raiseError("Could not replace attribute $attr values: " .
  813.                                         @ldap_error($link)@ldap_errno($link));
  814.             }
  815.             unset($this->_changes["replace"][$attr]);
  816.         }
  817.  
  818.         // all went well, so _original (server) becomes _attributes (local copy)
  819.         $this->_original = $this->_attributes;
  820.  
  821.         $return = true;
  822.         return $return;
  823.     }
  824.  
  825.     /**
  826.     * Returns the right attribute name
  827.     *
  828.     * @param string $attr Name of attribute
  829.     *
  830.     * @access protected
  831.     * @return string The right name of the attribute
  832.     */
  833.     protected function _getAttrName($attr)
  834.     {
  835.         $name strtolower($attr);
  836.         if (array_key_exists($name$this->_map)) {
  837.             $attr $this->_map[$name];
  838.         }
  839.         return $attr;
  840.     }
  841.  
  842.     /**
  843.     * Returns a reference to the LDAP-Object of this entry
  844.     *
  845.     * @access public
  846.     * @return Net_LDAP2|Net_LDAP2_Error  Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error
  847.     */
  848.     public function &getLDAP()
  849.     {
  850.         if (!$this->_ldap instanceof Net_LDAP2{
  851.             $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object');
  852.             return $err;
  853.         else {
  854.             return $this->_ldap;
  855.         }
  856.     }
  857.  
  858.     /**
  859.     * Sets a reference to the LDAP-Object of this entry
  860.     *
  861.     * After setting a Net_LDAP2 object, calling update() will use that object for
  862.     * updating directory contents. Use this to dynamicly switch directorys.
  863.     *
  864.     * @param Net_LDAP2 &$ldap Net_LDAP2 object that this entry should be connected to
  865.     *
  866.     * @access public
  867.     * @return true|Net_LDAP2_Error
  868.     */
  869.     public function setLDAP(&$ldap)
  870.     {
  871.         if (!$ldap instanceof Net_LDAP2{
  872.             return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object");
  873.         else {
  874.             $this->_ldap =$ldap;
  875.             return true;
  876.         }
  877.     }
  878.  
  879.     /**
  880.     * Marks the entry as new/existing.
  881.     *
  882.     * If an Entry is marked as new, it will be added to the directory
  883.     * when calling {@link update()}.
  884.     * If the entry is marked as old ($mark = false), then the entry is
  885.     * assumed to be present in the directory server wich results in
  886.     * modification when calling {@link update()}.
  887.     *
  888.     * @access public
  889.     * @param boolean $mark Value to set, defaults to "true"
  890.     */
  891.     public function markAsNew($mark = true)
  892.     {
  893.         $this->_new = ($mark)? true : false;
  894.     }
  895.  
  896.     /**
  897.     * Applies a regular expression onto a single- or multivalued attribute (like preg_match())
  898.     *
  899.     * This method behaves like PHPs preg_match() but with some exceptions.
  900.     * If you want to retrieve match information, then you MUST pass the
  901.     * $matches parameter via reference! otherwise you will get no matches.
  902.     * Since it is possible to have multi valued attributes the $matches
  903.     * array will have a additionally numerical dimension (one for each value):
  904.     * <code>
  905.     * $matches = array(
  906.     *         0 => array (usual preg_match() returnarray),
  907.     *         1 => array (usual preg_match() returnarray)
  908.     *     )
  909.     * </code>
  910.     * Please note, that $matches will be initialized to an empty array inside.
  911.     *
  912.     * Usage example:
  913.     * <code>
  914.     * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', &$matches);
  915.     * if ( $result === true ){
  916.     *     echo "First match: ".$matches[0][1];   // Match of value 1, content of first bracket
  917.     * } else {
  918.     *     if ( Net_LDAP2::isError($result) ) {
  919.     *         echo "Error: ".$result->getMessage();
  920.     *     } else {
  921.     *         echo "No match found.";
  922.     *     }
  923.     * }
  924.     * </code>
  925.     *
  926.     * Please note that it is important to test for an Net_LDAP2_Error, because objects are
  927.     * evaluating to true by default, thus if a error occured, and you only check using "==" then
  928.     * you get misleading results. Use the "identical" (===) operator to test for matches to
  929.     * avoid this as shown above.
  930.     *
  931.     * @param string $regex     The regular expression
  932.     * @param string $attr_name The attribute to search in
  933.     * @param array  $matches   (optional, PASS BY REFERENCE!) Array to store matches in
  934.     *
  935.     * @return boolean|Net_LDAP2_Error TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong
  936.     */
  937.     public function preg_match($regex$attr_name$matches = array())
  938.     {
  939.         $matches = array();
  940.  
  941.         // fetch attribute values
  942.         $attr $this->getValue($attr_name'all');
  943.         if (Net_LDAP2::isError($attr)) {
  944.             return $attr;
  945.         else {
  946.             unset($attr['count']);
  947.         }
  948.  
  949.         // perform preg_match() on all values
  950.         $match = false;
  951.         foreach ($attr as $thisvalue{
  952.             $matches_int = array();
  953.             if (preg_match($regex$thisvalue$matches_int)) {
  954.                 $match = true;
  955.                 array_push($matches$matches_int)// store matches in reference
  956.             }
  957.         }
  958.         return $match;
  959.     }
  960.  
  961.     /**
  962.     * Tells if the entry is consiedered as new (not present in the server)
  963.     *
  964.     * Please note, that this doesn't tell you if the entry is present on the server.
  965.     * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there.
  966.     *
  967.     * @return boolean 
  968.     */
  969.     public function isNew()
  970.     {
  971.         return $this->_new;
  972.     }
  973.  
  974.  
  975.     /**
  976.     * Is this entry going to be deleted once update() is called?
  977.     *
  978.     * @return boolean 
  979.     */
  980.     public function willBeDeleted()
  981.     {
  982.         return $this->_delete;
  983.     }
  984.  
  985.     /**
  986.     * Is this entry going to be moved once update() is called?
  987.     *
  988.     * @return boolean 
  989.     */
  990.     public function willBeMoved()
  991.     {
  992.         return ($this->dn(!== $this->currentDN());
  993.     }
  994.  
  995.     /**
  996.     * Returns always the original DN
  997.     *
  998.     * If an entry will be moved but {@link update()} was not called,
  999.     * {@link dn()} will return the new DN. This method however, returns
  1000.     * always the current active DN.
  1001.     *
  1002.     * @return string 
  1003.     */
  1004.     public function currentDN()
  1005.     {
  1006.         return $this->_dn;
  1007.     }
  1008.  
  1009.     /**
  1010.     * Returns the attribute changes to be carried out once update() is called
  1011.     *
  1012.     * @return array 
  1013.     */
  1014.     public function getChanges()
  1015.     {
  1016.         return $this->_changes;
  1017.     }
  1018. }
  1019. ?>

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