PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Ldap/Attribute.php

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