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

Source for file ldap2.php

Documentation is available at ldap2.php

  1. <?php
  2. //
  3. // Pear DB LDAP2 - Database independent query interface definition
  4. // for PHP's LDAP extension with protocol version 2.
  5. //
  6. // Copyright (C) 2002-2003 Piotr Roszatycki <dexter@debian.org>
  7. //
  8. // Based on ldap.php
  9. // Copyright (C) 2002 Ludovico Magnocavallo <ludo@sumatrasolutions.com>
  10. //
  11. //  This library is free software; you can redistribute it and/or
  12. //  modify it under the terms of the GNU Lesser General Public
  13. //  License as published by the Free Software Foundation; either
  14. //  version 2.1 of the License, or (at your option) any later version.
  15. //
  16. //  This library is distributed in the hope that it will be useful,
  17. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19. //  Lesser General Public License for more details.
  20. //
  21. //  You should have received a copy of the GNU Lesser General Public
  22. //  License along with this library; if not, write to the Free Software
  23. //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  24. //
  25. // $Id: ldap2.php 302688 2010-08-23 11:10:32Z clockwerx $
  26. //
  27.  
  28. require_once 'DB/common.php';
  29.  
  30. /**
  31.  * LDAP2 DB interface class
  32.  *
  33.  * DB_ldap2 extends DB_common to provide DB compliant
  34.  * access to LDAP servers with protocol version 2.
  35.  *
  36.  * @author Piotr Roszatycki <dexter@debian.org>
  37.  * @version $Revision: 302688 $
  38.  * @package DB_ldap2
  39.  */
  40.  
  41. class DB_ldap2 extends DB_common
  42. {
  43.     // {{{ properties
  44.  
  45.     /**
  46.      * LDAP connection handler
  47.      * @access private
  48.      */
  49.     var $connection;
  50.  
  51.     /**
  52.      * list of actions which manipulate data
  53.      * @access private
  54.      */
  55.     var $action_manip = array(
  56.         'add''compare''delete''modify''mod_add''mod_del',
  57.         'mod_replace''rename');
  58.  
  59.     /**
  60.      * list of parameters for search actions
  61.      * @access private
  62.      */
  63.     var    $param_search = array(
  64.         'action''base_dn''attributes''attrsonly''sizelimit',
  65.         'timelimit''deref','sort');
  66.  
  67.     /**
  68.      * list of parameters for modify actions
  69.      * @access private
  70.      */
  71.     var    $param_modify = array(
  72.         'action''attribute''value''newrdn''newparent',
  73.         'deleteoldrdn');
  74.  
  75.     /**
  76.      * default parameters for query
  77.      * @access private
  78.      */
  79.     var $param = array();
  80.  
  81.     /**
  82.      * parameters for last query
  83.      * @access private
  84.      */
  85.     var $last_param = array();
  86.  
  87.     /**
  88.      * array contained row counters for last query
  89.      * @access private
  90.      */
  91.     var $row = array();
  92.  
  93.     /**
  94.      * array contained number of rows for last query
  95.      * @access private
  96.      */
  97.     var $num_rows = array();
  98.  
  99.     /**
  100.      * array contained entry handlers for last query
  101.      * @access private
  102.      */
  103.     var $entry = array();
  104.  
  105.     /**
  106.      * array contained number of rows affected by last query
  107.      * @access private
  108.      */
  109.     var $affected = 0;
  110.  
  111.     // }}}
  112.     // {{{ constructor
  113.  
  114.     /**
  115.      * Constructor, calls DB_common constructor
  116.      *
  117.      * @see DB_common::DB_common()
  118.      */
  119.     function DB_ldap2()
  120.     {
  121.         $this->DB_common();
  122.         $this->phptype 'ldap2';
  123.         $this->dbsyntax 'ldap2';
  124.         $this->features = array(
  125.             'prepare'       => false,
  126.             'pconnect'      => false,
  127.             'transactions'  => false,
  128.             'limit'         => false
  129.         );
  130.         $this->errorcode_map = array(
  131.             0x10 => DB_ERROR_NOSUCHFIELD,               // LDAP_NO_SUCH_ATTRIBUTE
  132.             0x11 => DB_ERROR_NOSUCHFIELD,               // LDAP_UNDEFINED_TYPE
  133.             0x12 => DB_ERROR_CONSTRAINT,                // LDAP_INAPPROPRIATE_MATCHING
  134.             0x13 => DB_ERROR_CONSTRAINT,                // LDAP_CONSTRAINT_VIOLATION
  135.             0x14 => DB_ERROR_ALREADY_EXISTS,            // LDAP_TYPE_OR_VALUE_EXISTS
  136.             0x15 => DB_ERROR_INVALID,                   // LDAP_INVALID_SYNTAX
  137.             0x20 => DB_ERROR_NOSUCHTABLE,               // LDAP_NO_SUCH_OBJECT
  138.             0x21 => DB_ERROR_NOSUCHTABLE,               // LDAP_ALIAS_PROBLEM
  139.             0x22 => DB_ERROR_INVALID,                   // LDAP_INVALID_DN_SYNTAX
  140.             0x23 => DB_ERROR_INVALID,                   // LDAP_IS_LEAF
  141.             0x24 => DB_ERROR_INVALID,                   // LDAP_ALIAS_DEREF_PROBLEM
  142.             0x30 => DB_ERROR_ACCESS_VIOLATION,          // LDAP_INAPPROPRIATE_AUTH
  143.             0x31 => DB_ERROR_ACCESS_VIOLATION,          // LDAP_INVALID_CREDENTIALS
  144.             0x32 => DB_ERROR_ACCESS_VIOLATION,          // LDAP_INSUFFICIENT_ACCESS
  145.             0x40 => DB_ERROR_MISMATCH,                  // LDAP_NAMING_VIOLATION
  146.             0x41 => DB_ERROR_CONSTRAINT,                // LDAP_OBJECT_CLASS_VIOLATION
  147.             0x44 => DB_ERROR_ALREADY_EXISTS,            // LDAP_ALREADY_EXISTS
  148.             0x51 => DB_ERROR_CONNECT_FAILED,            // LDAP_SERVER_DOWN
  149.             0x57 => DB_ERROR_SYNTAX                     // LDAP_FILTER_ERROR
  150.         );
  151.     }
  152.  
  153.     // }}}
  154.     // {{{ connect()
  155.  
  156.     /**
  157.      * Connect and bind to LDAPv2 server with either anonymous
  158.      * or authenticated bind depending on dsn info
  159.      *
  160.      * The format of the supplied DSN:
  161.      *
  162.      *  ldap2://binddn:bindpw@host:port/basedn
  163.      *
  164.      * I.e.:
  165.      *
  166.      *  ldap2://uid=dexter,ou=People,dc=example,dc=net:secret@127.0.0.1/dc=example,dc=net
  167.      *
  168.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  169.      * @param boolean $persistent kept for interface compatibility
  170.      * @return int DB_OK if successfully connected.
  171.      *  A DB error code is returned on failure.
  172.      */
  173.     function connect($dsninfo$persistent = false)
  174.     {
  175.         if (!PEAR::loadExtension('ldap')) {
  176.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  177.         }
  178.  
  179.         $this->dsn $dsninfo;
  180.         $type   $dsninfo['phptype'];
  181.         $user   $dsninfo['username'];
  182.         $pw     $dsninfo['password'];
  183.         $host   $dsninfo['hostspec'];
  184.         $port   = empty($dsninfo['port']? 389 : $dsninfo['port'];
  185.  
  186.         $this->param = array(
  187.             'action' =>     'search',
  188.             'base_dn' =>    $this->base_dn $dsninfo['database'],
  189.             'attributes' => array(),
  190.             'attrsonly' =>  0,
  191.             'sizelimit' =>  0,
  192.             'timelimit' =>  0,
  193.             'deref' =>      LDAP_DEREF_NEVER,
  194.             'attribute' =>  '',
  195.             'value' =>      '',
  196.             'newrdn' =>     '',
  197.             'newparent' =>  '',
  198.             'deleteoldrdn'=>false,
  199.             'sort' =>       ''
  200.         );
  201.         $this->last_param $this->param;
  202.         $this->setOption("seqname_format""sn=%s," $dsninfo['database']);
  203.         $this->fetchmode = DB_FETCHMODE_ASSOC;
  204.  
  205.         if ($host{
  206.             $conn @ldap_connect($host$port);
  207.         else {
  208.             return $this->raiseError("unknown host $host");
  209.         }
  210.         if (!$conn{
  211.             return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  212.         }
  213.         if ($user && $pw{
  214.             $bind @ldap_bind($conn$user$pw);
  215.         else {
  216.             $bind @ldap_bind($conn);
  217.         }
  218.         if (!$bind{
  219.             return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  220.         }
  221.         $this->connection $conn;
  222.         return DB_OK;
  223.     }
  224.  
  225.     // }}}
  226.     // {{{ disconnect()
  227.  
  228.     /**
  229.      * Unbinds from LDAP server
  230.      *
  231.      * @return int ldap_unbind() return value
  232.      */
  233.     function disconnect()
  234.     {
  235.         $ret @ldap_unbind($this->connection);
  236.         $this->connection = null;
  237.         return $ret;
  238.     }
  239.  
  240.     // }}}
  241.     // {{{ simpleQuery()
  242.  
  243.     /**
  244.      * Performs a request against the LDAP server
  245.      *
  246.      * The type of request depend on $query parameter.  If $query is string,
  247.      * perform simple searching query with filter in $query parameter.
  248.      * If $query is array, the first element of array is filter string
  249.      * (for reading operations) or data array (for writing operations).
  250.      * Another elements of $query array are query parameters which overrides
  251.      * the default parameters.
  252.      *
  253.      * The following parameters can be passed for search queries:<br />
  254.      * <li />base_dn
  255.      * <li />attributes - array, the attributes that shall be returned
  256.      * <li />attrsonly
  257.      * <li />sizelimit - integer, the max number of results to be returned
  258.      * <li />timelimit - integer, the timelimit after which to stop searching
  259.      * <li />deref -
  260.      * <li/>sort - string, which tells the attribute name by which to sort
  261.      *
  262.      *
  263.      * I.e.:
  264.      * <code>
  265.      * // search queries
  266.      * // 'base_dn' is not given, so the one passed to connect() will be used
  267.      * $db->simpleQuery("uid=dexter");
  268.      *
  269.      * // base_dn is given
  270.      * // the 'attributes' key defines the attributes that shall be returned
  271.      * // 'sort' defines the sort order of the data
  272.      * $db->simpleQuery(array(
  273.      *      'uid=dexter',
  274.      *      'base_dn' => 'ou=People,dc=example,dc=net',
  275.      *      'attributes'=>array('dn','o','l'),
  276.      *      'sort'=>'o'
  277.      * ));
  278.      *
  279.      * // use this kind of query for adding data
  280.      * $db->simpleQuery(
  281.      *      array(
  282.      *          array(
  283.      *              'dn' => 'cn=Piotr Roszatycki,dc=example,dc=com',
  284.      *              'objectClass' => array('top', 'person'),
  285.      *              'cn' => 'Piotr Roszatycki',
  286.      *              'sn' => 'Roszatycki'),
  287.      *          'action' => 'add'
  288.      * ));
  289.      *
  290.      * @param mixed $query the ldap query
  291.      * @return int result from LDAP function for failure queries,
  292.      *  DB_OK for successful queries or DB Error object if wrong syntax
  293.      */
  294.     function simpleQuery$query)
  295.     {
  296.         if (is_array($query)) {
  297.             $last_param $query;
  298.             $query (isset($query[0]$query[0'objectClass=*');
  299.             unset($last_param[0]);
  300.         else {
  301.             $last_param = array();
  302.         }
  303.         $action (isset($last_param['action']$last_param['action'$this->param['action']);
  304.         // check if the given action is a valid modifier action, i.e. 'search'
  305.         if (!$this->isManip($action)) {
  306.             $this->last_param $this->param;
  307.             foreach($this->param_search as $k{
  308.                 if (isset($last_param[$k])) {
  309.                     $this->last_param[$k$last_param[$k];
  310.                 }
  311.             }
  312.             extract($this->last_param);
  313.             // double escape char for filter: '(o=Przedsi\C4\99biorstwo)' => '(o=Przedsi\\C4\\99biorstwo)'
  314.             $this->last_query $query;
  315.             $filter str_replace('\\''\\\\'$query);
  316.             switch ($action{
  317.                 // ldap_search, *list, *read have the same arguments
  318.                 case 'search':
  319.                 case 'list':
  320.                 case 'read':
  321.                     $ldap_action = "ldap_$action";
  322.                     $result @$ldap_action($this->connection$base_dn$filter$attributes$attrsonly$sizelimit$timelimit$deref);
  323.                     break;
  324.                 default:
  325.                     return $this->ldapRaiseError(DB_ERROR_SYNTAX);
  326.             }
  327.             if (!$result{
  328.                 return $this->ldapRaiseError();
  329.             }
  330.             $this->row[$result= 0; // reset the row counter.
  331.             $numrows $this->numrows($result);
  332.             if (is_object($numrows)) {
  333.                 return $numrows;
  334.             }
  335.             $this->num_rows[$result$numrows;
  336.             $this->affected = 0;
  337.             if ($sort{
  338.                 ldap_sort($this->connection,$result,$sort);
  339.             }
  340.             return $result;
  341.         else {
  342.             // If first argument is an array, it contains the entry with DN.
  343.             if (is_array($query)) {
  344.                 $entry $query;
  345.                 $dn $entry['dn'];
  346.                 unset($entry['dn']);
  347.             else {
  348.                 $entry = array();
  349.                 $dn $query;
  350.             }
  351.             $this->last_param $this->param;
  352.             foreach($this->param_modify as $k{
  353.                 if (isset($last_param[$k])) {
  354.                     $this->last_param[$k$last_param[$k];
  355.                 }
  356.             }
  357.             extract($this->last_param);
  358.             $this->last_query $query;
  359.             switch ($action{
  360.                 case 'add':
  361.                 case 'modify':
  362.                 case 'mod_add':
  363.                 case 'mod_del':
  364.                 case 'mod_replace':
  365.                     $ldap_action = "ldap_$action";
  366.                     $result @$ldap_action($this->connection$dn$entry);
  367.                     break;
  368.                 case 'compare':
  369.                     $result @ldap_compare($this->connection$dn$attribute$value);
  370.                     break;
  371.                 case 'delete':
  372.                     $result @ldap_delete($this->connection$dn);
  373.                     break;
  374.                 case 'rename':
  375.                     $result @ldap_rename($this->connection$dn$newrdn$newparent$deleteoldrdn);
  376.                     break;
  377.                 default:
  378.                     return $this->ldapRaiseError(DB_ERROR_SYNTAX);
  379.             }
  380.             if (!$result{
  381.                 return $this->ldapRaiseError();
  382.             }
  383.             $this->affected = 1;
  384.             return DB_OK;
  385.         }
  386.     }
  387.  
  388.     // }}}
  389.     // {{{ nextResult()
  390.  
  391.     /**
  392.      * Move the internal ldap result pointer to the next available result
  393.      *
  394.      * @param valid ldap result resource
  395.      *
  396.      * @access public
  397.      *
  398.      * @return true if a result is available otherwise return false
  399.      */
  400.     function nextResult($result)
  401.     {
  402.         return @ldap_next_entry($result);
  403.     }
  404.  
  405.     // }}}
  406.     // {{{ fetchRow()
  407.  
  408.     /**
  409.      * Fetch and return a row of data (it uses fetchInto for that)
  410.      * @param $result LDAP result identifier
  411.      * @param   $fetchmode  format of fetched row array
  412.      * @param   $rownum     the absolute row number to fetch
  413.      *
  414.      * @return  array   a row of data, or false on error
  415.      */
  416.     function fetchRow($result$fetchmode = DB_FETCHMODE_DEFAULT$rownum=null)
  417.     {
  418.         if ($fetchmode == DB_FETCHMODE_DEFAULT{
  419.             $fetchmode $this->fetchmode;
  420.         }
  421.         $res $this->fetchInto($result$arr$fetchmode$rownum);
  422.         if ($res !== DB_OK{
  423.             return $res;
  424.         }
  425.         return $arr;
  426.     }
  427.  
  428.     // }}}
  429.     // {{{ fetchInto()
  430.  
  431.     /**
  432.      * Fetch a row and insert the data into an existing array.
  433.      *
  434.      * DB_FETCHMODE_ORDERED returns a flat array of values
  435.      * ("value", "val1", "val2").
  436.      *
  437.      * DB_FETCHMODE_ASSOC returns an array of structuralized data
  438.      * ("field_name1" => "value", "field_name2" => array("val1", "val2")).
  439.      *
  440.      * @param $result PostgreSQL result identifier
  441.      * @param $arr (reference) array where data from the row is stored
  442.      * @param $fetchmode how the array data should be indexed
  443.      * @param $rownum the row number to fetch
  444.      *
  445.      * @return int DB_OK on success, a DB error code on failure
  446.      */
  447.     function fetchInto($result&$arr$fetchmode$rownum=null)
  448.     {
  449.     if ($rownum !== null{
  450.         // $rownum is unimplemented, yet
  451.         return null;
  452.     }
  453.         $rownum $this->row[$result];
  454.         if ($rownum >= $this->num_rows[$result]{
  455.             return null;
  456.         }
  457.     if ($rownum == 0{
  458.         $entry @ldap_first_entry($this->connection$result);
  459.     else {
  460.         $entry @ldap_next_entry($this->connection$this->entry[$result]);
  461.     }
  462.     $this->entry[$result$entry;
  463.         if (!$entry{
  464.             $errno = ldap_errno($this->connection);
  465.             if (!$err{
  466.                 return null;
  467.             }
  468.             return $this->ldapRaiseError();
  469.         }
  470.  
  471.     switch ($fetchmode{
  472.     case DB_FETCHMODE_ORDERED:
  473.             $arr = array();
  474.         if (!($attr @ldap_get_attributes($this->connection$entry))) {
  475.             $errno = ldap_errno($this->connection);
  476.             if (!$err{
  477.                     return null;
  478.             }
  479.             return $this->ldapRaiseError();
  480.             }
  481.         if ($attr["count"== 0{
  482.         if (!($arr[@ldap_get_dn($this->connection$entry))) {
  483.                 $errno = ldap_errno($this->connection);
  484.                 if (!$err{
  485.                     return null;
  486.                 }
  487.                 return $this->ldapRaiseError();
  488.         }
  489.             else {
  490.         while (list($attr_name$attr_valeach($attr)) {
  491.                 if ($attr_val["count"== 1{
  492.                     $arr[$attr_val[0];
  493.             elseif ($attr_val["count"> 1{
  494.             for ($i=0; $i<$attr_val["count"]$i++{
  495.                     $arr[$attr_val[$i];
  496.             }
  497.             }
  498.         }
  499.         }
  500.         break;
  501.     case DB_FETCHMODE_ASSOC:
  502.             $arr = array();
  503.         if (!($arr["dn"@ldap_get_dn($this->connection$entry))) {
  504.             $errno = ldap_errno($this->connection);
  505.             if (!$err{
  506.                     return null;
  507.             }
  508.             return $this->ldapRaiseError();
  509.             }
  510.         if (!($attr @ldap_get_attributes($this->connection$entry))) {
  511.             $errno = ldap_errno($this->connection);
  512.             if (!$err{
  513.                     return null;
  514.             }
  515.             return $this->ldapRaiseError();
  516.             }
  517.         while (list($attr_name$attr_valeach($attr)) {
  518.             if ($attr_val["count"== 1{
  519.                 $arr[strtolower($attr_name)$attr_val[0];
  520.         elseif ($attr_val["count"> 1{
  521.             for ($i=0; $i<$attr_val["count"]$i++{
  522.                 $arr[strtolower($attr_name)][$i$attr_val[$i];
  523.             }
  524.         }
  525.         }
  526.         break;
  527.     }
  528.  
  529.         $this->row[$result= ++$rownum;
  530.         return DB_OK;
  531.     }
  532.  
  533.     // }}}
  534.     // {{{ freeResult()
  535.  
  536.     /**
  537.      * Free the internal resources associated with $result.
  538.      *
  539.      * @param $result int LDAP result identifier or DB statement identifier
  540.      *
  541.      * @return bool TRUE on success, FALSE if $result is invalid
  542.      */
  543.     function freeResult($result)
  544.     {
  545.         if (is_resource($result)) {
  546.             return @ldap_free_result($result);
  547.         }
  548.         if (!isset($this->prepare_tokens[(int)$result])) {
  549.             return false;
  550.         }
  551.         unset($this->prepare_tokens[(int)$result]);
  552.         unset($this->prepare_types[(int)$result]);
  553.         unset($this->prepared_queries[(int)$result]);
  554.         unset($this->row[(int)$result]);
  555.         unset($this->num_rows[(int)$result]);
  556.         unset($this->entry[(int)$result]);
  557.         $this->affected = 0;
  558.         $this->last_param $this->param;
  559.         $this->attributes = null;
  560.         $this->sorting '';
  561.         return true;
  562.     }
  563.  
  564.     // }}}
  565.     // {{{ quote()
  566.  
  567.     /**
  568.     * Quote the given string so it can be safely used within string delimiters
  569.     * in a query.
  570.     *
  571.     * @param $string mixed Data to be quoted
  572.     *
  573.     * @return mixed "NULL" string, quoted string or original data
  574.     */
  575.     function quote($str = null)
  576.     {
  577.         $str str_replace(array('\\''"')array('\\\\''\\"')$str);
  578.         return $str;
  579.     }
  580.  
  581.     // }}}
  582.     // {{{ numCols()
  583.  
  584.     /**
  585.      * Get the number of columns in a result set. This function
  586.      * is used only for compatibility reasons.
  587.      *
  588.      * @param $result resource LDAP result identifier
  589.      *
  590.      * @return int DB_ERROR_NOT_CAPABLE error code
  591.      */
  592.     function numCols($result)
  593.     {
  594.         return $this->ldapRaiseError(DB_ERROR_NOT_CAPABLE);
  595.     }
  596.  
  597.     // }}}
  598.     // {{{ numRows()
  599.  
  600.     /**
  601.      * Get the number of rows in a result set.
  602.      *
  603.      * @param $result resource LDAP result identifier
  604.      *
  605.      * @return int the number of rows in $result
  606.      */
  607.     function numRows($result)
  608.     {
  609.         $rows @ldap_count_entries($this->connection$result);
  610.         if ($rows === null{
  611.             return $this->ldapRaiseError();
  612.         }
  613.         return $rows;
  614.     }
  615.  
  616.     // }}}
  617.     // {{{ errorNative()
  618.  
  619.     /**
  620.      * Get the native error code of the last error (if any) that
  621.      * occured on the current connection.
  622.      *
  623.      * @return int native LDAP error code
  624.      */
  625.     function errorNative()
  626.     {
  627.         return ldap_error($this->connection);
  628.     }
  629.  
  630.     // }}}
  631.     // {{{ affectedRows()
  632.  
  633.     /**
  634.      * Gets the number of rows affected by the last query.
  635.      * if the last query was a select, returns 0.
  636.      *
  637.      * @return int number of rows affected by the last query or DB_ERROR
  638.      */
  639.     function affectedRows()
  640.     {
  641.         return $this->affected;
  642.     }
  643.  
  644.     // }}}
  645.     // {{{ getTables()
  646.  
  647.     /**
  648.      * @deprecated
  649.      */
  650.     function getTables()
  651.     {
  652.         return $this->ldapRaiseError(DB_ERROR_NOT_CAPABLE);
  653.     }
  654.  
  655.     // }}}
  656.     // {{{ getListOf()
  657.  
  658.     /**
  659.      * Returns the query needed to get some backend info. This function is
  660.      * used only for compatibility reasons.
  661.      *
  662.      * @return int DB_ERROR_NOT_CAPABLE error code
  663.      */
  664.     function getListOf($type)
  665.     {
  666.         return $this->ldapRaiseError(DB_ERROR_NOT_CAPABLE);
  667.     }
  668.  
  669.     // }}}
  670.     // {{{ isManip()
  671.  
  672.     /**
  673.      * Tell whether an action is a data manipulation action (add, compare,
  674.      * delete, modify, mod_add, mod_del, mod_replace, rename)
  675.      *
  676.      * @param string $action the query
  677.      *
  678.      * @return boolean whether $query is a data manipulation action
  679.      */
  680.     function isManip($action)
  681.     {
  682.         return(in_array($action$this->action_manip));
  683.     }
  684.  
  685.     // }}}
  686.     // {{{ base()
  687.  
  688.     /**
  689.      * @deprecated
  690.      */
  691.     function base($base_dn = null)
  692.     {
  693.         $this->q_base_dn ($base_dn !== null$base_dn : null;
  694.         return true;
  695.     }
  696.  
  697.     // }}}
  698.     // {{{ ldapSetBaseDN()
  699.  
  700.     /**
  701.      * @deprecated
  702.      */
  703.     function ldapSetBaseDN($base_dn = null)
  704.     {
  705.         $this->base_dn ($base_dn !== null$base_dn $this->d_base_dn;
  706.         $this->q_base_dn '';
  707.         return true;
  708.     }
  709.  
  710.     // }}}
  711.     // {{{ ldapSetAction()
  712.  
  713.     /**
  714.      * @deprecated
  715.      */
  716.     function ldapSetAction($action 'search')
  717.     {
  718.         $this->action $action;
  719.         $this->q_action '';
  720.         return true;
  721.     }
  722.  
  723.     // }}}
  724.     // {{{ nextId()
  725.  
  726.     /**
  727.      * Get the next value in a sequence.
  728.      *
  729.      * LDAP provides transactions for only one entry and we need to
  730.      * prevent race condition. If unique value before and after modify
  731.      * aren't equal then wait and try again.
  732.      *
  733.      * @param string $seq_name the sequence name
  734.      * @param bool $ondemand whether to create the sequence on demand
  735.      *
  736.      * @return sequence integer, or a DB error
  737.      */
  738.     function nextId($seq_name$ondemand = true)
  739.     {
  740.     $seq_dn $this->getSequenceName($seq_name);
  741.         $repeat = 0;
  742.         do {
  743.             // Get the sequence entry
  744.         $this->expectError(DB_ERROR_NOSUCHTABLE);
  745.             $data $this->getRow(array('objectClass=*''action'=>'read''base_dn'=>$seq_dn));
  746.         $this->popExpect();
  747.  
  748.             if (DB::isError($data)) {
  749.                 if ($ondemand && $repeat == 0
  750.                 && $data->getCode(== DB_ERROR_NOSUCHTABLE{
  751.                 // Try to create sequence and repeat
  752.                     $repeat = 1;
  753.                     $data $this->createSequence($seq_name);
  754.                     if (DB::isError($data)) {
  755.                         return $this->ldapRaiseError($data);
  756.                     }
  757.                 else {
  758.                     // Other error
  759.                     return $this->ldapRaiseError($data);
  760.                 }
  761.             else {
  762.                 // Increment sequence value
  763.                 $data['cn']++;
  764.                 // Unique identificator of transaction
  765.                 $seq_unique mt_rand();
  766.                 $data['uid'$seq_unique;
  767.                 // Modify the LDAP entry
  768.                 $data $this->simpleQuery(array($data'action'=>'modify'));
  769.                 if (DB::isError($data)) {
  770.                     return $this->ldapRaiseError($data);
  771.                 }
  772.                 // Get the entry and check if it contains our unique value
  773.             $data $this->getRow(array('objectClass=*''action'=>'read''base_dn'=>$seq_dn));
  774.                 if (DB::isError($data)) {
  775.                     return $this->ldapRaiseError($data);
  776.                 }
  777.                 if ($data['uid'!= $seq_unique{
  778.                     // It is not our entry. Wait a little time and repeat
  779.                     sleep(1);
  780.                     $repeat = 1;
  781.                 else {
  782.                     $repeat = 0;
  783.                 }
  784.             }
  785.         while ($repeat);
  786.  
  787.         if (DB::isError($data)) {
  788.             return $data;
  789.         }
  790.         return $data['cn'];
  791.     }
  792.  
  793.     // }}}
  794.     // {{{ createSequence()
  795.  
  796.     /**
  797.      * Create the sequence
  798.      *
  799.      * The sequence entry is based on core schema with extensibleObject,
  800.      * so it should work with any LDAP server which doesn't check schema
  801.      * or supports extensibleObject object class.
  802.      *
  803.      * Format of the entry:
  804.      *
  805.      *  dn: $seq_dn
  806.      *  objectClass: top
  807.      *  objectClass: extensibleObject
  808.      *  sn: $seq_id
  809.      *  cn: $seq_value
  810.      *  uid: $seq_uniq
  811.      *
  812.      * @param string $seq_name the sequence name
  813.      *
  814.      * @return mixed DB_OK on success or DB error on error
  815.      */
  816.     function createSequence($seq_name)
  817.     {
  818.     $seq_dn $this->getSequenceName($seq_name);
  819.  
  820.         // Create the sequence entry
  821.         $data = array(
  822.             'dn' => $seq_dn,
  823.             'objectclass' => array('top''extensibleObject'),
  824.             'sn' => $seq_name,
  825.             'cn' => 0,
  826.             'uid' => 0
  827.         );
  828.  
  829.         // Add the LDAP entry
  830.         $data $this->simpleQuery(array($data'action'=>'add'));
  831.         return $data;
  832.     }
  833.  
  834.     // }}}
  835.     // {{{ dropSequence()
  836.  
  837.     /**
  838.      * Drop a sequence
  839.      *
  840.      * @param string $seq_name the sequence name
  841.      *
  842.      * @return mixed DB_OK on success or DB error on error
  843.      */
  844.     function dropSequence($seq_name)
  845.     {
  846.         $seq_dn $this->getSequenceName($seq_name);
  847.  
  848.         // Delete the sequence entry
  849.         $data = array(
  850.             'dn' => $seq_dn,
  851.         );
  852.         $data $this->simpleQuery(array($data'action'=>'delete'));
  853.         return $data;
  854.     }
  855.  
  856.     // }}}
  857.     // {{{ ldapRaiseError()
  858.  
  859.     /**
  860.      * Generate error message for LDAP errors.
  861.      *
  862.      * @param int $errno error number
  863.      *
  864.      * @return mixed DB_OK on success or DB error on error
  865.      */
  866.     function ldapRaiseError($errno = null)
  867.     {
  868.         if ($errno === null{
  869.             $errno $this->errorCode(ldap_errno($this->connection));
  870.         }
  871.         if ($this->last_param['action'!== null{
  872.             return $this->raiseError($errnonullnull,
  873.                         sprintf('%s base="%s" filter="%s"',
  874.                             $this->last_param['action'$this->last_param['action'$this->param['action'],
  875.                             $this->last_param['base_dn'$this->last_param['base_dn'$this->param['base_dn'],
  876.                             is_array($this->last_query"" $this->last_query
  877.                         ),
  878.                         $errno == @ldap_error($this->connection)
  879.                     );
  880.         else {
  881.             return $this->raiseError($errnonullnull"???",
  882.                         @ldap_error($this->connection));
  883.         }
  884.     }
  885.  
  886.     // }}}
  887.     // {{{ prepare()
  888.  
  889.  
  890.     /**
  891.      * Prepares a query for multiple execution with execute().
  892.      * This behaviour is emulated for LDAP backend.
  893.      * prepare() requires a generic query as an array with special
  894.      * characters (wildcards) as values.
  895.      *
  896.      * Types of wildcards:
  897.      *   ? - a quoted scalar value, i.e. strings, integers
  898.      *   & - requires a file name, the content of the file
  899.      *       insert into the query (i.e. saving binary data
  900.      *       in a db)
  901.      *   ! - value is inserted 'as is'
  902.      *
  903.      * Example:
  904.      *
  905.      *  $sth = $dbh->prepare(
  906.      *      array(
  907.      *             array(
  908.      *                 'dn' => '?',
  909.      *                 'objectClass' => '?',
  910.      *                 'cn' => '?',
  911.      *                 'sn' => '?',
  912.      *                 'description' => '&'
  913.      *             ),
  914.      *          'action' => 'add'
  915.      *      );
  916.      *  );
  917.      *
  918.      *  $sigfile = "/home/dexter/.signature";
  919.      *  $res = $dbh->execute($sth, array(
  920.      *      'cn=Piotr Roszatycki,dc=example,dc=com',
  921.      *      array('top', 'person'),
  922.      *      'Piotr Roszatycki', 'Roszatycki', $sigfile
  923.      *  ));
  924.      *
  925.      * @param mixed the query to prepare
  926.      *
  927.      * @return resource handle for the query
  928.      *
  929.      * @see execute
  930.      */
  931.     function prepare($query)
  932.     {
  933.     if (!is_array($query)) {
  934.         return parent::prepare($query);
  935.     elseif (is_array($query&& isset($query[0]&&
  936.         !$this->isManip(isset($query['action']$query['action'$this->param['action'])
  937.     {
  938.         $filter $query[0];
  939.             $tokens preg_split("/[\&\?\!]/"$filter);
  940.             $token = 0;
  941.             $types = array();
  942.  
  943.             for ($i = 0; $i strlen($filter)$i++{
  944.                 switch ($filter[$i]{
  945.                     case '?':
  946.                         $types[$token++= DB_PARAM_SCALAR;
  947.                         break;
  948.                     case '&':
  949.                         $types[$token++= DB_PARAM_OPAQUE;
  950.                         break;
  951.                     case '!':
  952.                         $types[$token++= DB_PARAM_MISC;
  953.                         break;
  954.                 }
  955.             }
  956.  
  957.             $this->prepare_tokens[&$tokens;
  958.             end($this->prepare_tokens);
  959.  
  960.             $k key($this->prepare_tokens);
  961.             $this->prepare_types[$k$types;
  962.             $this->prepared_queries[$k&$query;
  963.  
  964.             return $k;
  965.         elseif(is_array($query&& isset($query[0]&& is_array($query[0])) {
  966.             $tokens = array();
  967.             $types = array();
  968.  
  969.         foreach ($query[0as $k=>$v{
  970.         $tokens[$k$v;
  971.                 switch ($v{
  972.                     case '?':
  973.                         $types[$k= DB_PARAM_SCALAR;
  974.                         break;
  975.                     case '&':
  976.                         $types[$k= DB_PARAM_OPAQUE;
  977.                         break;
  978.                     case '!':
  979.                         $types[$k= DB_PARAM_MISC;
  980.                         break;
  981.             default:
  982.             $types[$k= null;
  983.                 }
  984.         }
  985.  
  986.             $this->prepare_tokens[&$tokens;
  987.             end($this->prepare_tokens);
  988.  
  989.             $k key($this->prepare_tokens);
  990.             $this->prepare_types[$k$types;
  991.             $this->prepared_queries[$k&$query;
  992.  
  993.             return $k;
  994.     else {
  995.         return parent::prepare($query);
  996.     }
  997.     }
  998.  
  999.     // }}}
  1000.     // {{{ executeEmulateQuery()
  1001.  
  1002.     /**
  1003.      * Emulates the execute statement.
  1004.      *
  1005.      * @param resource $stmt query handle from prepare()
  1006.      * @param array    $data numeric array containing the
  1007.      *                        data to insert into the query
  1008.      *
  1009.      * @return mixed an array containing the real query run when emulating
  1010.      *  prepare/execute.  A DB error code is returned on failure.
  1011.      *
  1012.      * @see execute()
  1013.      */
  1014.     function executeEmulateQuery($stmt$data = false)
  1015.     {
  1016.     $query &$this->prepared_queries[$stmt];
  1017.  
  1018.     if (!is_array($query)) {
  1019.         return parent::executeEmulateQuery($stmt$data);
  1020.     elseif (is_array($query&& isset($query[0]&&
  1021.         !$this->isManip(isset($query['action']$query['action'$this->param['action'])
  1022.     {
  1023.         $p &$this->prepare_tokens;
  1024.  
  1025.             if (!isset($this->prepare_tokens[$stmt]||
  1026.             !is_array($this->prepare_tokens[$stmt]||
  1027.             !sizeof($this->prepare_tokens[$stmt]))
  1028.             {
  1029.             return $this->raiseError(DB_ERROR_INVALID);
  1030.             }
  1031.  
  1032.             $qq &$this->prepare_tokens[$stmt];
  1033.             $qp sizeof($qq- 1;
  1034.  
  1035.             if ((!$data && $qp > 0||
  1036.                 (!is_array($data&& $qp > 1||
  1037.                 (is_array($data&& $qp sizeof($data)))
  1038.             {
  1039.                 $this->last_query $this->prepared_queries[$stmt];
  1040.                 return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  1041.             }
  1042.  
  1043.         $realquery $query;
  1044.             $realquery[0$qq[0];
  1045.             for ($i = 0; $i $qp$i++{
  1046.                 $type $this->prepare_types[$stmt][$i];
  1047.                 if ($type == DB_PARAM_OPAQUE{
  1048.                     if (is_array($data)) {
  1049.                         $fp fopen($data[$i]'r');
  1050.                     else {
  1051.                         $fp fopen($data'r');
  1052.                     }
  1053.  
  1054.                     $pdata '';
  1055.  
  1056.                     if ($fp{
  1057.                         while (($buf fread($fp4096)) != false{
  1058.                             $pdata .= $buf;
  1059.                         }
  1060.                     }
  1061.                 else {
  1062.                     if (is_array($data)) {
  1063.                         $pdata &$data[$i];
  1064.                     else {
  1065.                         $pdata &$data;
  1066.                     }
  1067.                 }
  1068.  
  1069.                 $realquery[0.= ($type != DB_PARAM_MISC$this->quote($pdata$pdata;
  1070.                 $realquery[0.= $qq[$i + 1];
  1071.             }
  1072.  
  1073.             return $realquery;
  1074.  
  1075.         elseif(is_array($query&& isset($query[0]&& is_array($query[0])) {
  1076.  
  1077.         $p &$this->prepare_tokens;
  1078.  
  1079.             if (!isset($this->prepare_tokens[$stmt]||
  1080.             !is_array($this->prepare_tokens[$stmt]||
  1081.             !sizeof($this->prepare_tokens[$stmt]))
  1082.             {
  1083.             return $this->raiseError(DB_ERROR_INVALID);
  1084.             }
  1085.  
  1086.             $qq &$this->prepare_tokens[$stmt];
  1087.         $realquery $query;
  1088.  
  1089.         $i = 0;
  1090.         foreach ($qq as $k=>$v{
  1091.                 $type $this->prepare_types[$stmt][$k];
  1092.  
  1093.                 if ($type !== null{
  1094.  
  1095.                 if (!isset($data||
  1096.                     (is_array($data&& !isset($data[$i]))
  1097.             {
  1098.                     $this->last_query $this->prepared_queries[$stmt];
  1099.                     return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  1100.                 }
  1101.  
  1102.                 if ($type == DB_PARAM_OPAQUE{
  1103.                     if (is_array($data)) {
  1104.                             $fp fopen($data[$i++]'r');
  1105.                     else {
  1106.                             $fp fopen($data'r');
  1107.                     }
  1108.  
  1109.                     $pdata '';
  1110.  
  1111.                     if ($fp{
  1112.                             while (($buf fread($fp4096)) != false{
  1113.                             $pdata .= $buf;
  1114.                             }
  1115.                     }
  1116.                     elseif ($type !== null{
  1117.                     if (is_array($data)) {
  1118.                             $pdata &$data[$i++];
  1119.                     else {
  1120.                             $pdata &$data;
  1121.                     }
  1122.                     }
  1123.  
  1124.             $realquery[0][$k$pdata;
  1125.         }
  1126.         }
  1127.  
  1128.             return $realquery;
  1129.  
  1130.     else {
  1131.         return parent::executeEmulateQuery($stmt$data);
  1132.     }
  1133.     }
  1134.  
  1135.     // }}}
  1136.     // {{{ ldapSetParam()
  1137.  
  1138.     /**
  1139.      * Sets the default parameters for query.
  1140.      *
  1141.      * @param string $param the name of parameter for search actions (action,
  1142.      *  base_dn, attributes, attrsonly, sizelimit, timelimit, deref) or
  1143.      *  modify actions (action, attribute, value, newrdn, newparent,
  1144.      *  deleteoldrdn).
  1145.      * @param string $value the value of parameter
  1146.      *
  1147.      * @return mixed DB_OK on success or DB error on error
  1148.      *
  1149.      * @see ldapGetParam()
  1150.      */
  1151.     function ldapSetParam($param$value)
  1152.     {
  1153.         if (isset($this->param[$param])) {
  1154.             $this->param[$param$value;
  1155.             return DB_OK;
  1156.         }
  1157.         return $this->raiseError("unknown LDAP parameter $param");
  1158.     }
  1159.  
  1160.     // }}}
  1161.     // {{{ ldapGetParam()
  1162.  
  1163.     /**
  1164.      * Gets the default parameters for query.
  1165.      *
  1166.      * @param string $param the name of parameter for search or modify
  1167.      *  actions.
  1168.      *
  1169.      * @return mixed value of parameter on success or DB error on error
  1170.      *
  1171.      * @see ldapSetParam()
  1172.      */
  1173.     function ldapGetParam($param)
  1174.     {
  1175.         if (isset($this->param[$param])) {
  1176.             return $this->param[$param];
  1177.         }
  1178.         return $this->raiseError("unknown LDAP parameter $param");
  1179.     }
  1180.  
  1181.     // }}}
  1182.     // {{{ ldapSetOption()
  1183.  
  1184.     /**
  1185.      * Sets the value of the given option.
  1186.      *
  1187.      * @param int $option the specified option
  1188.      * @param mixed $newval the value of specified option
  1189.      *
  1190.      * @return bool DB_OK on success or DB error on error
  1191.      *
  1192.      * @see ldapGetOption()
  1193.      */
  1194.     function ldapSetOption($option$newval)
  1195.     {
  1196.         if (@ldap_set_option($this->connection$option$newval)) {
  1197.             return DB_OK;
  1198.         }
  1199.         return $this->raiseError("failed to set LDAP option");
  1200.     }
  1201.  
  1202.     // }}}
  1203.     // {{{ ldapGetOption()
  1204.  
  1205.     /**
  1206.      * Gets the current value for given option.
  1207.      *
  1208.      * @param int $option the specified option
  1209.      * @param mixed $retval (reference) the new value of specified option
  1210.      *
  1211.      * @return bool DB_OK on success or DB error on error
  1212.      *
  1213.      * @see ldapSetOption()
  1214.      */
  1215.     function ldapGetOption($option&$retval)
  1216.     {
  1217.         if (@ldap_get_option($this->connection$option$retval)) {
  1218.             return DB_OK;
  1219.         }
  1220.         return $this->raiseError("failed to get LDAP option");
  1221.     }
  1222.  
  1223.     // }}}
  1224.     // {{{ ldapExplodeDN()
  1225.  
  1226.     /**
  1227.      * Splits the DN and breaks it up into its component parts.
  1228.      * Each part is known as Relative Distinguished Name, or RDN.
  1229.      *
  1230.      * @param string $dn the DN to split
  1231.      * @param int $with_attrib 0 to get RDNs with the attributes
  1232.      *  or 1 to get only values.
  1233.      *
  1234.      * @return array an array of all those components
  1235.      */
  1236.     function ldapExplodeDN($dn$with_attrib = 0)
  1237.     {
  1238.         $arr = ldap_explode_dn($dn$with_attrib ? 1 : 0);
  1239.         unset($arr['count']);
  1240.         return $arr;
  1241.     }
  1242.  
  1243. }
  1244.  
  1245. ?>

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