Completed
Push — master ( 4d2b11...999b16 )
by Patrick
03:34
created

LDAPServer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 9.4285
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 $ldapLink;
65
    protected $connect;
66
    protected $binder;
67
    public $user_base;
68
    public $group_base;
69
70
    protected function __construct()
71
    {
72
        $this->ldapLink = null;
73
        $this->binder = null;
74
    }
75
76
    public function __destruct()
77
    {
78
    }
79
80
    public function __wakeup()
81
    {
82
        $this->ldapLink = 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->ldapLink !== null)
102
        {
103
            ldap_close($this->ldapLink);
104
        }
105
        $this->connect = $connectStr;
106
        $this->ldapLink = ldap_connect($this->connect);
107
        if($this->ldapLink === false)
108
        {
109
            $this->ldapLink = null;
110
            return false;
111
        }
112
        ldap_set_option($this->ldapLink, LDAP_OPT_PROTOCOL_VERSION, 3);
113
        return true;
114
    }
115
116
    public function disconnect()
117
    {
118
        if($this->ldapLink !== null)
119
        {
120
            ldap_close($this->ldapLink);
121
            $this->ldapLink = 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->ldapLink === 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->ldapLink);
143
        }
144
        try
145
        {
146
            $res = ldap_bind($this->ldapLink, $cn, $password);
147
        }
148
        catch(\Exception $ex)
149
        {
150
            $this->ldapLink = ldap_connect($this->connect);
151
            $res = @ldap_bind($this->ldapLink, $cn, $password);
152
        }
153
        return $res;
154
    }
155
156
    public function unbind()
157
    {
158
        if($this->ldapLink === null)
159
        {
160
            return true;
161
        }
162
        return @ldap_unbind($this->ldapLink);
163
    }
164
165
    private function fixObject($object, &$delete = false)
166
    {
167
        $entity = $object;
168
        if(!is_array($object))
169
        {
170
            $entity = $object->to_array();
171
        }
172
        unset($entity['dn']);
173
        $keys = array_keys($entity);
174
        $count = count($keys);
175
        for($i = 0; $i < $count; $i++)
176
        {
177
            if(is_array($entity[$keys[$i]]))
178
            {
179
                $array = $entity[$keys[$i]];
180
                unset($entity[$keys[$i]]);
181
                $count1 = count($array);
182
                for($j = 0; $j < $count1; $j++)
183
                {
184
                    if(isset($array[$j]))
185
                    {
186
                        $entity[$keys[$i]][$j] = $array[$j];
187
                    }
188
                }
189
            }
190
            else if($delete !== false && $entity[$keys[$i]] === null)
191
            {
192
                $delete[$keys[$i]] = array();
193
                unset($entity[$keys[$i]]);
194
            }
195
        }
196
        return $entity;
197
    }
198
199
    public function create($object)
200
    {
201
        $dn = ldap_escape($object['dn'], true);
202
        $entity = $this->fixObject($object);
203
        $ret = ldap_add($this->ldapLink, $dn, $entity);
204
        if($ret === false)
205
        {
206
            throw new \Exception('Failed to create object with dn='.$dn);
207
        }
208
        return $ret;
209
    }
210
211
    /**
212
     * Get the LDAP filter represented by the passed object
213
     *
214
     * @param boolean|string|\Data\Filter $filter The fiter to use
215
     *
216
     * @return string The filter in LDAP format
217
     */
218
    private function filterToString($filter)
219
    {
220
        if($filter === false)
221
        {
222
            return '(objectclass=*)';
223
        }
224
        if(is_string($filter))
225
        {
226
            return $filter;
227
        }
228
        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...
229
    }
230
231
    private function searchResultToArray($searchResult)
232
    {
233
        if($searchResult === false)
234
        {
235
            return false;
236
        }
237
        $res = ldap_get_entries($this->ldapLink, $searchResult);
238
        if(is_array($res))
239
        {
240
            $ldap = $res;
241
            $res = array();
242
            for($i = 0; $i < $ldap['count']; $i++)
243
            {
244
                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...
245
            }
246
        }
247
        return $res;
248
    }
249
250
    public function read($baseDN, $filter = false, $single = false, $attributes = false)
251
    {
252
        $filterStr = $this->filterToString($filter);
253
        if($this->ldapLink === null)
254
        {
255
            throw new \Exception('Not connected');
256
        }
257
        try
258
        {
259
            if($single === true)
260
            {
261
                $searchResult = @ldap_read($this->ldapLink, $baseDN, $filterStr);
262
                return $this->searchResultToArray($searchResult);
263
            }
264
            if($attributes !== false)
265
            {
266
                $searchResult = @ldap_list($this->ldapLink, $baseDN, $filterStr, $attributes);
267
                return $this->searchResultToArray($searchResult);
268
            }
269
            $searchResult = @ldap_list($this->ldapLink, $baseDN, $filterStr);
270
            return $this->searchResultToArray($searchResult);
271
        }
272
        catch(\Exception $e)
273
        {
274
            throw new \Exception($e->getMessage().' '.$filterStr, $e->getCode(), $e);
275
        }
276
    }
277
278
    public function count($baseDN, $filter = false)
279
    {
280
        $filterStr = $this->filterToString($filter);
281
        if($this->ldapLink === null)
282
        {
283
            throw new \Exception('Not connected');
284
        }
285
        try
286
        {
287
            $searchResult = ldap_list($this->ldapLink, $baseDN, $filterStr, array('dn'));
288
        }
289
        catch(\Exception $e)
290
        {
291
            throw new \Exception($e->getMessage().' '.$filterStr, $e->getCode(), $e);
292
        }
293
        if($searchResult === false)
294
        {
295
            return false;
296
        }
297
        return ldap_count_entries($this->ldapLink, $searchResult);
298
    }
299
300
    public function update($object)
301
    {
302
        $distinguishedName = ldap_escape($object['dn'], true);
303
        $delete = array();
304
        $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...
305
        $ret = false;
306
        if(!empty($entity))
307
        {
308
            $ret = @ldap_mod_replace($this->ldapLink, $distinguishedName, $entity);
309
            if($ret === false)
310
            {
311
                throw new \Exception('Failed to update object with dn='.$distinguishedName.'('.ldap_errno($this->ldapLink).':'.ldap_error($this->ldapLink).') '.print_r($entity, true));
312
            }
313
        }
314
        if(!empty($delete))
315
        {
316
            $ret = @ldap_mod_del($this->ldapLink, $distinguishedName, $delete);
317
        }
318
        return $ret;
319
    }
320
321
    public function delete($distinguishedName)
322
    {
323
        return ldap_delete($this->ldapLink, $distinguishedName);
324
    }
325
}
326
327