|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Ldap |
|
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: Attribute.php 22996 2010-09-22 17:01:46Z sgehrig $ |
|
20 */ |
|
21 |
|
22 /** |
|
23 * @see Zend_Ldap_Converter |
|
24 */ |
|
25 require_once 'Zend/Ldap/Converter.php'; |
|
26 |
|
27 /** |
|
28 * Zend_Ldap_Attribute is a collection of LDAP attribute related functions. |
|
29 * |
|
30 * @category Zend |
|
31 * @package Zend_Ldap |
|
32 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
33 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
34 */ |
|
35 class Zend_Ldap_Attribute |
|
36 { |
|
37 const PASSWORD_HASH_MD5 = 'md5'; |
|
38 const PASSWORD_HASH_SMD5 = 'smd5'; |
|
39 const PASSWORD_HASH_SHA = 'sha'; |
|
40 const PASSWORD_HASH_SSHA = 'ssha'; |
|
41 const PASSWORD_UNICODEPWD = 'unicodePwd'; |
|
42 |
|
43 /** |
|
44 * Sets a LDAP attribute. |
|
45 * |
|
46 * @param array $data |
|
47 * @param string $attribName |
|
48 * @param scalar|array|Traversable $value |
|
49 * @param boolean $append |
|
50 * @return void |
|
51 */ |
|
52 public static function setAttribute(array &$data, $attribName, $value, $append = false) |
|
53 { |
|
54 $attribName = strtolower($attribName); |
|
55 $valArray = array(); |
|
56 if (is_array($value) || ($value instanceof Traversable)) |
|
57 { |
|
58 foreach ($value as $v) |
|
59 { |
|
60 $v = self::_valueToLdap($v); |
|
61 if ($v !== null) $valArray[] = $v; |
|
62 } |
|
63 } |
|
64 else if ($value !== null) |
|
65 { |
|
66 $value = self::_valueToLdap($value); |
|
67 if ($value !== null) $valArray[] = $value; |
|
68 } |
|
69 |
|
70 if ($append === true && isset($data[$attribName])) |
|
71 { |
|
72 if (is_string($data[$attribName])) $data[$attribName] = array($data[$attribName]); |
|
73 $data[$attribName] = array_merge($data[$attribName], $valArray); |
|
74 } |
|
75 else |
|
76 { |
|
77 $data[$attribName] = $valArray; |
|
78 } |
|
79 } |
|
80 |
|
81 /** |
|
82 * Gets a LDAP attribute. |
|
83 * |
|
84 * @param array $data |
|
85 * @param string $attribName |
|
86 * @param integer $index |
|
87 * @return array|mixed |
|
88 */ |
|
89 public static function getAttribute(array $data, $attribName, $index = null) |
|
90 { |
|
91 $attribName = strtolower($attribName); |
|
92 if ($index === null) { |
|
93 if (!isset($data[$attribName])) return array(); |
|
94 $retArray = array(); |
|
95 foreach ($data[$attribName] as $v) |
|
96 { |
|
97 $retArray[] = self::_valueFromLdap($v); |
|
98 } |
|
99 return $retArray; |
|
100 } else if (is_int($index)) { |
|
101 if (!isset($data[$attribName])) { |
|
102 return null; |
|
103 } else if ($index >= 0 && $index<count($data[$attribName])) { |
|
104 return self::_valueFromLdap($data[$attribName][$index]); |
|
105 } else { |
|
106 return null; |
|
107 } |
|
108 } |
|
109 return null; |
|
110 } |
|
111 |
|
112 /** |
|
113 * Checks if the given value(s) exist in the attribute |
|
114 * |
|
115 * @param array $data |
|
116 * @param string $attribName |
|
117 * @param mixed|array $value |
|
118 * @return boolean |
|
119 */ |
|
120 public static function attributeHasValue(array &$data, $attribName, $value) |
|
121 { |
|
122 $attribName = strtolower($attribName); |
|
123 if (!isset($data[$attribName])) return false; |
|
124 |
|
125 if (is_scalar($value)) { |
|
126 $value = array($value); |
|
127 } |
|
128 |
|
129 foreach ($value as $v) { |
|
130 $v = self::_valueToLdap($v); |
|
131 if (!in_array($v, $data[$attribName], true)) { |
|
132 return false; |
|
133 } |
|
134 } |
|
135 return true; |
|
136 } |
|
137 |
|
138 /** |
|
139 * Removes duplicate values from a LDAP attribute |
|
140 * |
|
141 * @param array $data |
|
142 * @param string $attribName |
|
143 * @return void |
|
144 */ |
|
145 public static function removeDuplicatesFromAttribute(array &$data, $attribName) |
|
146 { |
|
147 $attribName = strtolower($attribName); |
|
148 if (!isset($data[$attribName])) return; |
|
149 $data[$attribName] = array_values(array_unique($data[$attribName])); |
|
150 } |
|
151 |
|
152 /** |
|
153 * Remove given values from a LDAP attribute |
|
154 * |
|
155 * @param array $data |
|
156 * @param string $attribName |
|
157 * @param mixed|array $value |
|
158 * @return void |
|
159 */ |
|
160 public static function removeFromAttribute(array &$data, $attribName, $value) |
|
161 { |
|
162 $attribName = strtolower($attribName); |
|
163 if (!isset($data[$attribName])) return; |
|
164 |
|
165 if (is_scalar($value)) { |
|
166 $value = array($value); |
|
167 } |
|
168 |
|
169 $valArray = array(); |
|
170 foreach ($value as $v) |
|
171 { |
|
172 $v = self::_valueToLdap($v); |
|
173 if ($v !== null) $valArray[] = $v; |
|
174 } |
|
175 |
|
176 $resultArray = $data[$attribName]; |
|
177 foreach ($valArray as $rv) { |
|
178 $keys = array_keys($resultArray, $rv); |
|
179 foreach ($keys as $k) { |
|
180 unset($resultArray[$k]); |
|
181 } |
|
182 } |
|
183 $resultArray = array_values($resultArray); |
|
184 $data[$attribName] = $resultArray; |
|
185 } |
|
186 |
|
187 /** |
|
188 * @param mixed $value |
|
189 * @return string|null |
|
190 */ |
|
191 private static function _valueToLdap($value) |
|
192 { |
|
193 return Zend_Ldap_Converter::toLdap($value); |
|
194 } |
|
195 |
|
196 /** |
|
197 * @param string $value |
|
198 * @return mixed |
|
199 */ |
|
200 private static function _valueFromLdap($value) |
|
201 { |
|
202 try { |
|
203 $return = Zend_Ldap_Converter::fromLdap($value, Zend_Ldap_Converter::STANDARD, false); |
|
204 if ($return instanceof DateTime) { |
|
205 return Zend_Ldap_Converter::toLdapDateTime($return, false); |
|
206 } else { |
|
207 return $return; |
|
208 } |
|
209 } catch (InvalidArgumentException $e) { |
|
210 return $value; |
|
211 } |
|
212 } |
|
213 |
|
214 /** |
|
215 * Converts a PHP data type into its LDAP representation |
|
216 * |
|
217 * @deprected use Zend_Ldap_Converter instead |
|
218 * @param mixed $value |
|
219 * @return string|null - null if the PHP data type cannot be converted. |
|
220 */ |
|
221 public static function convertToLdapValue($value) |
|
222 { |
|
223 return self::_valueToLdap($value); |
|
224 } |
|
225 |
|
226 /** |
|
227 * Converts an LDAP value into its PHP data type |
|
228 * |
|
229 * @deprected use Zend_Ldap_Converter instead |
|
230 * @param string $value |
|
231 * @return mixed |
|
232 */ |
|
233 public static function convertFromLdapValue($value) |
|
234 { |
|
235 return self::_valueFromLdap($value); |
|
236 } |
|
237 |
|
238 /** |
|
239 * Converts a timestamp into its LDAP date/time representation |
|
240 * |
|
241 * @param integer $value |
|
242 * @param boolean $utc |
|
243 * @return string|null - null if the value cannot be converted. |
|
244 */ |
|
245 public static function convertToLdapDateTimeValue($value, $utc = false) |
|
246 { |
|
247 return self::_valueToLdapDateTime($value, $utc); |
|
248 } |
|
249 |
|
250 /** |
|
251 * Converts LDAP date/time representation into a timestamp |
|
252 * |
|
253 * @param string $value |
|
254 * @return integer|null - null if the value cannot be converted. |
|
255 */ |
|
256 public static function convertFromLdapDateTimeValue($value) |
|
257 { |
|
258 return self::_valueFromLdapDateTime($value); |
|
259 } |
|
260 |
|
261 /** |
|
262 * Sets a LDAP password. |
|
263 * |
|
264 * @param array $data |
|
265 * @param string $password |
|
266 * @param string $hashType |
|
267 * @param string|null $attribName |
|
268 * @return null |
|
269 */ |
|
270 public static function setPassword(array &$data, $password, $hashType = self::PASSWORD_HASH_MD5, |
|
271 $attribName = null) |
|
272 { |
|
273 if ($attribName === null) { |
|
274 if ($hashType === self::PASSWORD_UNICODEPWD) { |
|
275 $attribName = 'unicodePwd'; |
|
276 } else { |
|
277 $attribName = 'userPassword'; |
|
278 } |
|
279 } |
|
280 |
|
281 $hash = self::createPassword($password, $hashType); |
|
282 self::setAttribute($data, $attribName, $hash, false); |
|
283 } |
|
284 |
|
285 /** |
|
286 * Creates a LDAP password. |
|
287 * |
|
288 * @param string $password |
|
289 * @param string $hashType |
|
290 * @return string |
|
291 */ |
|
292 public static function createPassword($password, $hashType = self::PASSWORD_HASH_MD5) |
|
293 { |
|
294 switch ($hashType) { |
|
295 case self::PASSWORD_UNICODEPWD: |
|
296 /* see: |
|
297 * http://msdn.microsoft.com/en-us/library/cc223248(PROT.10).aspx |
|
298 */ |
|
299 $password = '"' . $password . '"'; |
|
300 if (function_exists('mb_convert_encoding')) { |
|
301 $password = mb_convert_encoding($password, 'UTF-16LE', 'UTF-8'); |
|
302 } else if (function_exists('iconv')) { |
|
303 $password = iconv('UTF-8', 'UTF-16LE', $password); |
|
304 } else { |
|
305 $len = strlen($password); |
|
306 $new = ''; |
|
307 for($i=0; $i < $len; $i++) { |
|
308 $new .= $password[$i] . "\x00"; |
|
309 } |
|
310 $password = $new; |
|
311 } |
|
312 return $password; |
|
313 case self::PASSWORD_HASH_SSHA: |
|
314 $salt = substr(sha1(uniqid(mt_rand(), true), true), 0, 4); |
|
315 $rawHash = sha1($password . $salt, true) . $salt; |
|
316 $method = '{SSHA}'; |
|
317 break; |
|
318 case self::PASSWORD_HASH_SHA: |
|
319 $rawHash = sha1($password, true); |
|
320 $method = '{SHA}'; |
|
321 break; |
|
322 case self::PASSWORD_HASH_SMD5: |
|
323 $salt = substr(sha1(uniqid(mt_rand(), true), true), 0, 4); |
|
324 $rawHash = md5($password . $salt, true) . $salt; |
|
325 $method = '{SMD5}'; |
|
326 break; |
|
327 case self::PASSWORD_HASH_MD5: |
|
328 default: |
|
329 $rawHash = md5($password, true); |
|
330 $method = '{MD5}'; |
|
331 break; |
|
332 } |
|
333 return $method . base64_encode($rawHash); |
|
334 } |
|
335 |
|
336 /** |
|
337 * Sets a LDAP date/time attribute. |
|
338 * |
|
339 * @param array $data |
|
340 * @param string $attribName |
|
341 * @param integer|array|Traversable $value |
|
342 * @param boolean $utc |
|
343 * @param boolean $append |
|
344 * @return null |
|
345 */ |
|
346 public static function setDateTimeAttribute(array &$data, $attribName, $value, $utc = false, |
|
347 $append = false) |
|
348 { |
|
349 $convertedValues = array(); |
|
350 if (is_array($value) || ($value instanceof Traversable)) |
|
351 { |
|
352 foreach ($value as $v) { |
|
353 $v = self::_valueToLdapDateTime($v, $utc); |
|
354 if ($v !== null) $convertedValues[] = $v; |
|
355 } |
|
356 } |
|
357 else if ($value !== null) { |
|
358 $value = self::_valueToLdapDateTime($value, $utc); |
|
359 if ($value !== null) $convertedValues[] = $value; |
|
360 } |
|
361 self::setAttribute($data, $attribName, $convertedValues, $append); |
|
362 } |
|
363 |
|
364 /** |
|
365 * @param integer $value |
|
366 * @param boolean $utc |
|
367 * @return string|null |
|
368 */ |
|
369 private static function _valueToLdapDateTime($value, $utc) |
|
370 { |
|
371 if (is_int($value)) { |
|
372 return Zend_Ldap_Converter::toLdapDateTime($value, $utc); |
|
373 } |
|
374 else return null; |
|
375 } |
|
376 |
|
377 /** |
|
378 * Gets a LDAP date/time attribute. |
|
379 * |
|
380 * @param array $data |
|
381 * @param string $attribName |
|
382 * @param integer $index |
|
383 * @return array|integer |
|
384 */ |
|
385 public static function getDateTimeAttribute(array $data, $attribName, $index = null) |
|
386 { |
|
387 $values = self::getAttribute($data, $attribName, $index); |
|
388 if (is_array($values)) { |
|
389 for ($i = 0; $i<count($values); $i++) { |
|
390 $newVal = self::_valueFromLdapDateTime($values[$i]); |
|
391 if ($newVal !== null) $values[$i] = $newVal; |
|
392 } |
|
393 } |
|
394 else { |
|
395 $newVal = self::_valueFromLdapDateTime($values); |
|
396 if ($newVal !== null) $values = $newVal; |
|
397 } |
|
398 return $values; |
|
399 } |
|
400 |
|
401 /** |
|
402 * @param string|DateTime $value |
|
403 * @return integer|null |
|
404 */ |
|
405 private static function _valueFromLdapDateTime($value) |
|
406 { |
|
407 if ($value instanceof DateTime) { |
|
408 return $value->format('U'); |
|
409 } else if (is_string($value)) { |
|
410 try { |
|
411 return Zend_Ldap_Converter::fromLdapDateTime($value, false)->format('U'); |
|
412 } catch (InvalidArgumentException $e) { |
|
413 return null; |
|
414 } |
|
415 } else return null; |
|
416 } |
|
417 } |