Completed
Push — master ( b25e7b...4d2b11 )
by Patrick
03:36
created

LDAPServer::getError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 1
b 1
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
namespace LDAP;
3
4
/**
5
 * function ldap_escape
6
 * @author Chris Wright
7
 * @version 2.0
8
 * @param string $subject The subject string
9
 * @param bool $dn Treat subject as a DN if TRUE
0 ignored issues
show
Bug introduced by
There is no parameter named $dn. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
10
 * @param string|array $ignore Set of characters to leave untouched
11
 * @return string The escaped string
12
 */
13
function ldap_escape($subject, $distinguishedName = false, $ignore = NULL)
14
{
15
    // The base array of characters to escape
16
    // Flip to keys for easy use of unset()
17
    $search = array_flip($distinguishedName ? array('\\', '+', '<', '>', ';', '"', '#') : array('\\', '*', '(', ')', "\x00"));
18
19
    // Process characters to ignore
20
    if(is_array($ignore))
21
    {
22
        $ignore = array_values($ignore);
23
    }
24
    for($char = 0; isset($ignore[$char]); $char++)
25
    {
26
        unset($search[$ignore[$char]]);
27
    }
28
29
    // Flip $search back to values and build $replace array
30
    $search = array_keys($search); 
31
    $replace = array();
32
    foreach($search as $char)
33
    {
34
        $replace[] = sprintf('\\%02x', ord($char));
35
    }
36
37
    // Do the main replacement
38
    $result = str_replace($search, $replace, $subject);
39
40
    // Encode leading/trailing spaces in DN values
41
    if($distinguishedName)
42
    {
43
        $result = cleanupDN($result);
44
    }
45
46
    return $result;
47
}
48
49
function cleanupDN($distinguishedName)
50
{
51
    if($distinguishedName[0] == ' ')
52
    {
53
        $distinguishedName = '\\20'.substr($distinguishedName, 1);
54
    }
55
    if($distinguishedName[strlen($distinguishedName) - 1] == ' ')
56
    {
57
        $distinguishedName = substr($distinguishedName, 0, -1).'\\20';
58
    }
59
    return $distinguishedName;
60
}
61
62
class LDAPServer extends \Singleton
63
{
64
    protected $ds;
65
    protected $connect;
66
    protected $binder;
67
    public $user_base;
68
    public $group_base;
69
70
    protected function __construct()
71
    {
72
        $this->ds = null;
73
        $this->binder = null;
74
    }
75
76
    public function __destruct()
77
    {
78
    }
79
80
    public function __wakeup()
81
    {
82
        $this->ds = ldap_connect($this->connect);
83
    }
84
85
    private function getConnectString($name, $proto = false)
86
    {
87
        if(strstr($name, ':') !== false)
88
        {
89
            return $name;
90
        }
91
        if($proto !== 'ldap')
92
        {
93
            return $proto.'://'.$name;
94
        }
95
        return $name;
96
    }
97
98
    public function connect($name, $proto = false)
99
    {
100
        $connectStr = $this->getConnectString($name, $proto);
101
        if($this->ds !== null)
102
        {
103
            ldap_close($this->ds);
104
        }
105
        $this->connect = $connectStr;
106
        $this->ds      = ldap_connect($this->connect);
107
        if($this->ds === false)
108
        {
109
            $this->ds = null;
110
            return false;
111
        }
112
        ldap_set_option($this->ds, LDAP_OPT_PROTOCOL_VERSION, 3);
113
        return true;
114
    }
115
116
    public function disconnect()
117
    {
118
        if($this->ds !== null)
119
        {
120
            ldap_close($this->ds);
121
            $this->ds = null;
122
        }
123
        $this->connect = false;
124
    }
125
126
    /**
127
     * Bind (login0 to the LDAP Server
128
     *
129
     * @param string $cn The common name to bind with, null to bind anonymously
130
     * @param string $password The password to bind with, null to bind anonymously
131
     */
132
    public function bind($cn = null, $password = null)
133
    {
134
        $res = false;
135
        if($this->ds === null)
136
        {
137
            throw new \Exception('Not connected');
138
        }
139
        $this->binder = $cn;
140
        if($cn === null || $password === null)
141
        {
142
            return @ldap_bind($this->ds);
143
        }
144
        try
145
        {
146
            $res = ldap_bind($this->ds, $cn, $password);
147
        }
148
        catch(\Exception $ex)
149
        {
150
            $this->ds = ldap_connect($this->connect);
151
            $res = @ldap_bind($this->ds, $cn, $password);
152
        }
153
        return $res;
154
    }
155
156
    public function unbind()
157
    {
158
        if($this->ds === null)
159
        {
160
            return true;
161
        }
162
        return @ldap_unbind($this->ds);
163
    }
164
165
    public function getError()
166
    {
167
        return ldap_error($this->ds);
168
    }
169
170
    private function fixObject($object, &$delete = false)
171
    {
172
        $entity = $object;
173
        if(!is_array($object))
174
        {
175
            $entity = $object->to_array();
176
        }
177
        unset($entity['dn']);
178
        $keys = array_keys($entity);
179
        $count = count($keys);
180
        for($i = 0; $i < $count; $i++)
181
        {
182
            if(is_array($entity[$keys[$i]]))
183
            {
184
                $array = $entity[$keys[$i]];
185
                unset($entity[$keys[$i]]);
186
                $count1 = count($array);
187
                for($j = 0; $j < $count1; $j++)
188
                {
189
                    if(isset($array[$j]))
190
                    {
191
                        $entity[$keys[$i]][$j] = $array[$j];
192
                    }
193
                }
194
            }
195
            else if($delete !== false && $entity[$keys[$i]] === null)
196
            {
197
                $delete[$keys[$i]] = array();
198
                unset($entity[$keys[$i]]);
199
            }
200
        }
201
        return $entity;
202
    }
203
204
    public function create($object)
205
    {
206
        $dn = ldap_escape($object['dn'], true);
207
        $entity = $this->fixObject($object);
208
        $ret = ldap_add($this->ds, $dn, $entity);
209
        if($ret === false)
210
        {
211
            throw new \Exception('Failed to create object with dn='.$dn);
212
        }
213
        return $ret;
214
    }
215
216
    /**
217
     * Get the LDAP filter represented by the passed object
218
     *
219
     * @param boolean|string|\Data\Filter $filter The fiter to use
220
     *
221
     * @return string The filter in LDAP format
222
     */
223
    private function filterToString($filter)
224
    {
225
        if($filter === false)
226
        {
227
            return '(objectclass=*)';
228
        }
229
        if(is_string($filter))
230
        {
231
            return $filter;
232
        }
233
        return $filter->to_ldap_string();
0 ignored issues
show
Bug introduced by
It seems like $filter is not always an object, but can also be of type boolean. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
234
    }
235
236
    private function searchResultToArray($searchResult)
237
    {
238
        if($searchResult === false)
239
        {
240
            return false;
241
        }
242
        $res = ldap_get_entries($this->ds, $searchResult);
243
        if(is_array($res))
244
        {
245
            $ldap = $res;
246
            $res = array();
247
            for($i = 0; $i < $ldap['count']; $i++)
248
            {
249
                array_push($res, new LDAPObject($ldap[$i], $this));
0 ignored issues
show
Documentation introduced by
$this is of type this<LDAP\LDAPServer>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
250
            }
251
        }
252
        return $res;
253
    }
254
255
    public function read($baseDN, $filter = false, $single = false, $attributes = false)
256
    {
257
        $filterStr = $this->filterToString($filter);
258
        if($this->ds === null)
259
        {
260
            throw new \Exception('Not connected');
261
        }
262
        try
263
        {
264
            if($single === true)
265
            {
266
                $searchResult = @ldap_read($this->ds, $baseDN, $filterStr);
267
                return $this->searchResultToArray($searchResult);
268
            }
269
            if($attributes !== false)
270
            {
271
                $searchResult = @ldap_list($this->ds, $baseDN, $filterStr, $attributes);
272
                return $this->searchResultToArray($searchResult);
273
            }
274
            $searchResult = @ldap_list($this->ds, $baseDN, $filterStr);
275
            return $this->searchResultToArray($searchResult);
276
        }
277
        catch(\Exception $e)
278
        {
279
            throw new \Exception($e->getMessage().' '.$filterStr, $e->getCode(), $e);
280
        }
281
    }
282
283
    public function count($baseDN, $filter = false)
284
    {
285
        $filterStr = $this->filterToString($filter);
286
        if($this->ds === null)
287
        {
288
            throw new \Exception('Not connected');
289
        }
290
        try
291
        {
292
            $sr = ldap_list($this->ds, $baseDN, $filterStr, array('dn'));
293
        }
294
        catch(\Exception $e)
295
        {
296
            throw new \Exception($e->getMessage().' '.$filterStr, $e->getCode(), $e);
297
        }
298
        if($sr === false)
299
        {
300
            return false;
301
        }
302
        return ldap_count_entries($this->ds, $sr);
303
    }
304
305
    public function update($object)
306
    {
307
        $dn = ldap_escape($object['dn'], true);
308
        $delete = array();
309
        $entity = $this->fixObject($object, $delete);
0 ignored issues
show
Documentation introduced by
$delete is of type array, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
310
        $ret = false;
311
        if(!empty($entity))
312
        {
313
            $ret = @ldap_mod_replace($this->ds, $dn, $entity);
314
            if($ret === false)
315
            {
316
                throw new \Exception('Failed to update object with dn='.$dn.'('.ldap_errno($this->ds).':'.ldap_error($this->ds).') '.print_r($entity, true));
317
            }
318
        }
319
        if(!empty($delete))
320
        {
321
            $ret = @ldap_mod_del($this->ds, $dn, $delete);
322
        }
323
        return $ret;
324
    }
325
326
    public function delete($distinguishedName)
327
    {
328
        return ldap_delete($this->ds, $distinguishedName);
329
    }
330
}
331
332