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

Source for file Search.php

Documentation is available at Search.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3.  
  4. require_once 'PEAR.php';
  5.  
  6. /**
  7. * Result set of an LDAP search
  8. *
  9. @category Net
  10. @package  Net_LDAP
  11. @author   Tarjej Huse <tarjei@bergfald.no>
  12. @author   Benedikt Hallinger <beni@php.net>
  13. @license  http://www.gnu.org/copyleft/lesser.html LGPL
  14. @version  CVS $Id: Search.php,v 1.31 2008/03/19 08:10:54 beni Exp $
  15. @link     http://pear.php.net/package/Net_LDAP/
  16. */
  17. class Net_LDAP_Search extends PEAR
  18. {
  19.     /**
  20.     * Search result identifier
  21.     *
  22.     * @access private
  23.     * @var resource 
  24.     */
  25.     var $_search;
  26.  
  27.     /**
  28.     * LDAP resource link
  29.     *
  30.     * @access private
  31.     * @var resource 
  32.     */
  33.     var $_link;
  34.  
  35.     /**
  36.     * Net_LDAP object
  37.     *
  38.     * A reference of the Net_LDAP object for passing to Net_LDAP_Entry
  39.     *
  40.     * @access private
  41.     * @var object Net_LDAP 
  42.     */
  43.     var $_ldap;
  44.  
  45.     /**
  46.     * Result entry identifier
  47.     *
  48.     * @access private
  49.     * @var resource 
  50.     */
  51.     var $_entry = null;
  52.  
  53.     /**
  54.     * The errorcode the search got
  55.     *
  56.     * Some errorcodes might be of interest, but might not be best handled as errors.
  57.     * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search.
  58.     *               Incomplete results are returned. If you just want to check if there's anything in the search.
  59.     *               than this is a point to handle.
  60.     *           32 - no such object - search here returns a count of 0.
  61.     *
  62.     * @access private
  63.     * @var int 
  64.     */
  65.     var $_errorCode = 0; // if not set - sucess!
  66.  
  67.     /**
  68.     * What attributes we searched for
  69.     *
  70.     * The $attributes array contains the names of the searched attributes and gets
  71.     * passed from $Net_LDAP->search() so the Net_LDAP_Search object can tell
  72.     * what attributes was searched for ({@link _searchedAttrs())}
  73.     *
  74.     * This variable gets set from the constructor and returned
  75.     * from {@link _searchedAttrs()}
  76.     *
  77.     * @access private
  78.     * @var array 
  79.     */
  80.     var $_searchedAttrs = array();
  81.  
  82.     /**
  83.     * Cache variable for storing entries fetched internally
  84.     *
  85.     * This currently is only used by {@link pop_entry()}
  86.     *
  87.     * @access private
  88.     * @var array 
  89.     */
  90.     var $_entry_cache = false;
  91.  
  92.     /**
  93.     * Constructor
  94.     *
  95.     * @param resource          &$search    Search result identifier
  96.     * @param Net_LDAP|resource&$ldap      Net_LDAP object or just a LDAP-Link resource
  97.     * @param array             $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs})
  98.     *
  99.     * @access protected
  100.     */
  101.     function Net_LDAP_Search(&$search&$ldap$attributes = array())
  102.     {
  103.         $this->PEAR('Net_LDAP_Error');
  104.  
  105.         $this->setSearch($search);
  106.  
  107.         if (is_a($ldap'Net_LDAP')) {
  108.             $this->_ldap =$ldap;
  109.             $this->setLink($this->_ldap->getLink());
  110.         else {
  111.             $this->setLink($ldap);
  112.         }
  113.  
  114.         $this->_errorCode @ldap_errno($this->_link);
  115.  
  116.         if (is_array($attributes&& !empty($attributes)) {
  117.             $this->_searchedAttrs $attributes;
  118.         }
  119.     }
  120.  
  121.     /**
  122.     * Returns an array of entry objects
  123.     *
  124.     * @return array Array of entry objects.
  125.     */
  126.     function entries()
  127.     {
  128.         $entries = array();
  129.  
  130.         while ($entry $this->shiftEntry()) {
  131.             $entries[$entry;
  132.         }
  133.  
  134.         return $entries;
  135.     }
  136.  
  137.     /**
  138.     * Get the next entry in the searchresult.
  139.     *
  140.     * This will return a valid Net_LDAP_Entry object or false, so
  141.     * you can use this method to easily iterate over the entries inside
  142.     * a while loop.
  143.     *
  144.     * @return Net_LDAP_Entry|false Reference to Net_LDAP_Entry object or false
  145.     */
  146.     function &shiftEntry()
  147.     {
  148.         if ($this->count(== 0 {
  149.             $false = false;
  150.             return $false;
  151.         }
  152.  
  153.         if (is_null($this->_entry)) {
  154.             $this->_entry @ldap_first_entry($this->_link$this->_search);
  155.             $entry        = new Net_LDAP_Entry($this->_ldap$this->_entry);
  156.         else {
  157.             if (!$this->_entry @ldap_next_entry($this->_link$this->_entry)) {
  158.                 $false = false;
  159.                 return $false;
  160.             }
  161.             $entry = new Net_LDAP_Entry($this->_ldap$this->_entry);
  162.         }
  163.         return $entry;
  164.     }
  165.  
  166.     /**
  167.     * Alias function of shiftEntry() for perl-ldap interface
  168.     *
  169.     * @see shiftEntry()
  170.     */
  171.     function shift_entry()
  172.     {
  173.         $args func_get_args();
  174.         return call_user_func_array(array&$this'shiftEntry' )$args);
  175.     }
  176.  
  177.     /**
  178.     * Retrieve the next entry in the searchresult, but starting from last entry
  179.     *
  180.     * This is the opposite to {@link shiftEntry()} and is also very useful
  181.     * to be used inside a while loop.
  182.     *
  183.     * @return Net_LDAP_Entry|false
  184.     */
  185.     function popEntry()
  186.     {
  187.         if (false === $this->_entry_cache{
  188.             // fetch entries into cache if not done so far
  189.             $this->_entry_cache $this->entries();
  190.         }
  191.  
  192.         $return array_pop($this->_entry_cache);
  193.         return (null === $return)? false : $return;
  194.     }
  195.  
  196.     /**
  197.     * Alias function of popEntry() for perl-ldap interface
  198.     *
  199.     * @see popEntry()
  200.     */
  201.     function pop_entry()
  202.     {
  203.         $args func_get_args();
  204.         return call_user_func_array(array&$this'popEntry' )$args);
  205.     }
  206.  
  207.     /**
  208.     * Return entries sorted as array
  209.     *
  210.     * This returns a array with sorted entries and the values.
  211.     * Sorting is done with PHPs {@link array_multisort()}.
  212.     * This method relies on {@link as_struct()} to fetch the raw data of the entries.
  213.     *
  214.     * Please note that attribute names are case sensitive!
  215.     *
  216.     * Usage example:
  217.     * <code>
  218.     *   // to sort entries first by location, then by surename, but descending:
  219.     *   $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC);
  220.     * </code>
  221.     *
  222.     * @param array $attrs Array of attribute names to sort; order from left to right.
  223.     * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
  224.     *
  225.     * @return array|Net_LDAP_Error  Array with sorted entries or error
  226.     */
  227.     function sorted_as_struct($attrs = array('cn')$order = SORT_ASC)
  228.     {
  229.         /*
  230.         * Old Code, suitable and fast for single valued sorting
  231.         * This code should be used if we know that single valued sorting is desired,
  232.         * but we need some method to get that knowledge...
  233.         */
  234.         /*
  235.         $attrs = array_reverse($attrs);
  236.         foreach ($attrs as $attribute) {
  237.             if (!ldap_sort($this->_link, $this->_search, $attribute)){
  238.                 $this->raiseError("Sorting failed for Attribute " . $attribute);
  239.             }
  240.         }
  241.  
  242.         $results = ldap_get_entries($this->_link, $this->_search);
  243.  
  244.         unset($results['count']); //for tidier output
  245.         if ($order) {
  246.             return array_reverse($results);
  247.         } else {
  248.             return $results;
  249.         }*/
  250.  
  251.         /*
  252.         * New code: complete "client side" sorting
  253.         */
  254.         // first some parameterchecks
  255.         if (!is_array($attrs)) {
  256.             return PEAR::raiseError("Sorting failed: Parameterlist must be an array!");
  257.         }
  258.         if ($order != SORT_ASC && $order != SORT_DESC{
  259.             return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)");
  260.         }
  261.  
  262.         // fetch the entries data
  263.         $entries $this->as_struct();
  264.  
  265.         // now sort each entries attribute values
  266.         // this is neccessary because later we can only sort by one value,
  267.         // so we need the highest or lowest attribute now, depending on the
  268.         // selected ordering for that specific attribute
  269.         foreach ($entries as $dn => $entry{
  270.             foreach ($entry as $attr_name => $attr_values{
  271.                 sort($entries[$dn][$attr_name]);
  272.                 if ($order == SORT_DESC{
  273.                     array_reverse($entries[$dn][$attr_name]);
  274.                 }
  275.             }
  276.         }
  277.  
  278.         // reformat entrys array for later use with array_multisort()
  279.         $to_sort = array()// <- will be a numeric array similar to ldap_get_entries
  280.         foreach ($entries as $dn => $entry_attr{
  281.             $row       = array();
  282.             $row['dn'$dn;
  283.             foreach ($entry_attr as $attr_name => $attr_values{
  284.                 $row[$attr_name$attr_values;
  285.             }
  286.             $to_sort[$row;
  287.         }
  288.  
  289.         // Build columns for array_multisort()
  290.         // each requested attribute is one row
  291.         $columns = array();
  292.         foreach ($attrs as $attr_name{
  293.             foreach ($to_sort as $key => $row{
  294.                 $columns[$attr_name][$key=$to_sort[$key][$attr_name][0];
  295.             }
  296.         }
  297.  
  298.         // sort the colums with array_multisort, if there is something
  299.         // to sort and if we have requested sort columns
  300.         if (!empty($to_sort&& !empty($columns)) {
  301.             $sort_params '';
  302.             foreach ($attrs as $attr_name{
  303.                 $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', ';
  304.             }
  305.             eval("array_multisort($sort_params \$to_sort);")// perform sorting
  306.         }
  307.  
  308.         return $to_sort;
  309.     }
  310.  
  311.     /**
  312.     * Return entries sorted as objects
  313.     *
  314.     * This returns a array with sorted Net_LDAP_Entry objects.
  315.     * The sorting is actually done with {@link sorted_as_struct()}.
  316.     *
  317.     * Please note that attribute names are case sensitive!
  318.     *
  319.     * Usage example:
  320.     * <code>
  321.     *   // to sort entries first by location, then by surename, but descending:
  322.     *   $entries = $search->sorted(array('locality','sn'), SORT_DESC);
  323.     * </code>
  324.     *
  325.     * @param array $attrs Array of sort attributes to sort; order from left to right.
  326.     * @param int   $order Ordering direction, either constant SORT_ASC or SORT_DESC
  327.     *
  328.     * @return array|Net_LDAP_Error  Array with sorted Net_LDAP_Entries or error
  329.     */
  330.     function sorted($attrs = array('cn')$order = SORT_ASC)
  331.     {
  332.         $return = array();
  333.         $sorted $this->sorted_as_struct($attrs$order);
  334.         if (PEAR::isError($sorted)) {
  335.             return $sorted;
  336.         }
  337.         foreach ($sorted as $key => $row{
  338.             $entry $this->_ldap->getEntry($row['dn']$this->_searchedAttrs());
  339.             if (!PEAR::isError($entry)) {
  340.                 array_push($return$entry);
  341.             else {
  342.                 return $entry;
  343.             }
  344.         }
  345.         return $return;
  346.     }
  347.  
  348.     /**
  349.     * Return entries as array
  350.     *
  351.     * This method returns the entries and the selected attributes values as
  352.     * array.
  353.     * The first array level contains all found entries where the keys are the
  354.     * DNs of the entries. The second level arrays contian the entries attributes
  355.     * such that the keys is the lowercased name of the attribute and the values
  356.     * are stored in another indexed array. Note that the attribute values are stored
  357.     * in an array even if there is no or just one value.
  358.     *
  359.     * The array has the following structure:
  360.     * <code>
  361.     * $return = array(
  362.     *           'cn=foo,dc=example,dc=com' => array(
  363.     *                                                'sn'       => array('foo'),
  364.     *                                                'multival' => array('val1', 'val2', 'valN')
  365.     *                                             )
  366.     *           'cn=bar,dc=example,dc=com' => array(
  367.     *                                                'sn'       => array('bar'),
  368.     *                                                'multival' => array('val1', 'valN')
  369.     *                                             )
  370.     *           )
  371.     * </code>
  372.     *
  373.     * @return array      associative result array as described above
  374.     */
  375.     function as_struct()
  376.     {
  377.         $return  = array();
  378.         $entries $this->entries();
  379.         foreach ($entries as $entry{
  380.             $attrs            = array();
  381.             $entry_attributes $entry->attributes();
  382.             foreach ($entry_attributes as $attr_name{
  383.                 $attr_values $entry->getValue($attr_name'all');
  384.                 if (!is_array($attr_values)) {
  385.                     $attr_values = array($attr_values);
  386.                 }
  387.                 $attrs[$attr_name$attr_values;
  388.             }
  389.             $return[$entry->dn()$attrs;
  390.         }
  391.         return $return;
  392.     }
  393.  
  394.     /**
  395.     * Set the search objects resource link
  396.     *
  397.     * @param resource &$search Search result identifier
  398.     *
  399.     * @access public
  400.     * @return void 
  401.     */
  402.     function setSearch(&$search)
  403.     {
  404.         $this->_search $search;
  405.     }
  406.  
  407.     /**
  408.     * Set the ldap ressource link
  409.     *
  410.     * @param resource &$link Link identifier
  411.     *
  412.     * @access public
  413.     * @return void 
  414.     */
  415.     function setLink(&$link)
  416.     {
  417.         $this->_link $link;
  418.     }
  419.  
  420.     /**
  421.     * Returns the number of entries in the searchresult
  422.     *
  423.     * @return int Number of entries in search.
  424.     */
  425.     function count()
  426.     {
  427.         // this catches the situation where OL returned errno 32 = no such object!
  428.         if (!$this->_search{
  429.             return 0;
  430.         }
  431.         return @ldap_count_entries($this->_link$this->_search);
  432.     }
  433.  
  434.     /**
  435.     * Get the errorcode the object got in its search.
  436.     *
  437.     * @return int The ldap error number.
  438.     */
  439.     function getErrorCode()
  440.     {
  441.         return $this->_errorCode;
  442.     }
  443.  
  444.     /**
  445.     * Destructor
  446.     *
  447.     * @access protected
  448.     */
  449.     function _Net_LDAP_Search()
  450.     {
  451.         @ldap_free_result($this->_search);
  452.     }
  453.  
  454.     /**
  455.     * Closes search result
  456.     *
  457.     * @return void 
  458.     */
  459.     function done()
  460.     {
  461.         $this->_Net_LDAP_Search();
  462.     }
  463.  
  464.     /**
  465.     * Return the attribute names this search selected
  466.     *
  467.     * @return array 
  468.     * @see $_searchedAttrs
  469.     * @access private
  470.     */
  471.     function _searchedAttrs()
  472.     {
  473.         return $this->_searchedAttrs;
  474.     }
  475.  
  476.     /**
  477.     * Tells if this search exceeds a sizelimit
  478.     *
  479.     * @return boolean 
  480.     */
  481.     function sizeLimitExceeded()
  482.     {
  483.         return ($this->getErrorCode(== 4);
  484.     }
  485. }
  486.  
  487. ?>

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