web/lib/Zend/Ldap/Converter.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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: Converter.php 22996 2010-09-22 17:01:46Z sgehrig $
       
    20  */
       
    21 
       
    22 /**
       
    23  * Zend_Ldap_Converter is a collection of useful LDAP related conversion functions.
       
    24  *
       
    25  * @category   Zend
       
    26  * @package    Zend_Ldap
       
    27  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    28  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    29  */
       
    30 class Zend_Ldap_Converter
       
    31 {
       
    32     const STANDARD         = 0;
       
    33     const BOOLEAN          = 1;
       
    34     const GENERALIZED_TIME = 2;
       
    35 
       
    36     /**
       
    37      * Converts all ASCII chars < 32 to "\HEX"
       
    38      *
       
    39      * @see Net_LDAP2_Util::asc2hex32() from Benedikt Hallinger <beni@php.net>
       
    40      * @link http://pear.php.net/package/Net_LDAP2
       
    41      * @author Benedikt Hallinger <beni@php.net>
       
    42      *
       
    43      * @param  string $string String to convert
       
    44      * @return string
       
    45      */
       
    46     public static function ascToHex32($string)
       
    47     {
       
    48         for ($i = 0; $i<strlen($string); $i++) {
       
    49             $char = substr($string, $i, 1);
       
    50             if (ord($char)<32) {
       
    51                 $hex = dechex(ord($char));
       
    52                 if (strlen($hex) == 1) $hex = '0' . $hex;
       
    53                 $string = str_replace($char, '\\' . $hex, $string);
       
    54             }
       
    55         }
       
    56         return $string;
       
    57     }
       
    58 
       
    59     /**
       
    60      * Converts all Hex expressions ("\HEX") to their original ASCII characters
       
    61      *
       
    62      * @see Net_LDAP2_Util::hex2asc() from Benedikt Hallinger <beni@php.net>,
       
    63      * heavily based on work from DavidSmith@byu.net
       
    64      * @link http://pear.php.net/package/Net_LDAP2
       
    65      * @author Benedikt Hallinger <beni@php.net>, heavily based on work from DavidSmith@byu.net
       
    66      *
       
    67      * @param  string $string String to convert
       
    68      * @return string
       
    69      */
       
    70     public static function hex32ToAsc($string)
       
    71     {
       
    72         $string = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $string);
       
    73         return $string;
       
    74     }
       
    75 
       
    76 	/**
       
    77      * Convert any value to an LDAP-compatible value.
       
    78      *
       
    79      * By setting the <var>$type</var>-parameter the conversion of a certain
       
    80      * type can be forced
       
    81      *
       
    82      * @todo write more tests
       
    83      *
       
    84      * @param	mixed 	$value 	The value to convert
       
    85      * @param	int   	$ytpe  	The conversion type to use
       
    86      * @return	string
       
    87      * @throws	Zend_Ldap_Converter_Exception
       
    88      */
       
    89     public static function toLdap($value, $type = self::STANDARD)
       
    90     {
       
    91         try {
       
    92             switch ($type) {
       
    93                 case self::BOOLEAN:
       
    94                     return self::toldapBoolean($value);
       
    95                     break;
       
    96                 case self::GENERALIZED_TIME:
       
    97                     return self::toLdapDatetime($value);
       
    98                     break;
       
    99                 default:
       
   100                     if (is_string($value)) {
       
   101                         return $value;
       
   102                     } else if (is_int($value) || is_float($value)) {
       
   103                         return (string)$value;
       
   104                     } else if (is_bool($value)) {
       
   105                         return self::toldapBoolean($value);
       
   106                     } else if (is_object($value)) {
       
   107                         if ($value instanceof DateTime) {
       
   108                             return self::toLdapDatetime($value);
       
   109                         } else if ($value instanceof Zend_Date) {
       
   110                             return self::toLdapDatetime($value);
       
   111                         } else {
       
   112                             return self::toLdapSerialize($value);
       
   113                         }
       
   114                     } else if (is_array($value)) {
       
   115                         return self::toLdapSerialize($value);
       
   116                     } else if (is_resource($value) && get_resource_type($value) === 'stream') {
       
   117                         return stream_get_contents($value);
       
   118                     } else {
       
   119                         return null;
       
   120                     }
       
   121                     break;
       
   122             }
       
   123         } catch (Exception $e) {
       
   124             throw new Zend_Ldap_Converter_Exception($e->getMessage(), $e->getCode(), $e);
       
   125         }
       
   126     }
       
   127 
       
   128     /**
       
   129      * Converts a date-entity to an LDAP-compatible date-string
       
   130      *
       
   131      * The date-entity <var>$date</var> can be either a timestamp, a
       
   132      * DateTime Object, a string that is parseable by strtotime() or a Zend_Date
       
   133      * Object.
       
   134      *
       
   135      * @param	integer|string|DateTimt|Zend_Date		$date	The date-entity
       
   136      * @param	boolean									$asUtc	Whether to return the LDAP-compatible date-string
       
   137      *                          								as UTC or as local value
       
   138      * @return	string
       
   139      * @throws	InvalidArgumentException
       
   140      */
       
   141     public static function toLdapDateTime($date, $asUtc = true)
       
   142     {
       
   143         if (!($date instanceof DateTime)) {
       
   144             if (is_int($date)) {
       
   145                 $date = new DateTime('@' . $date);
       
   146                 $date->setTimezone(new DateTimeZone(date_default_timezone_get()));
       
   147             } else if (is_string($date)) {
       
   148                 $date = new DateTime($date);
       
   149             } else if ($date instanceof Zend_Date) {
       
   150                 $date = new DateTime($date->get(Zend_Date::ISO_8601));
       
   151             } else {
       
   152                 throw new InvalidArgumentException('Parameter $date is not of the expected type');
       
   153             }
       
   154         }
       
   155         $timezone = $date->format('O');
       
   156         if (true === $asUtc) {
       
   157             $date->setTimezone(new DateTimeZone('UTC'));
       
   158             $timezone = 'Z';
       
   159         }
       
   160         if ( '+0000' === $timezone ) {
       
   161             $timezone = 'Z';
       
   162         }
       
   163         return $date->format('YmdHis') . $timezone;
       
   164     }
       
   165 
       
   166     /**
       
   167      * Convert a boolean value to an LDAP-compatible string
       
   168      *
       
   169      * This converts a boolean value of TRUE, an integer-value of 1 and a
       
   170      * case-insensitive string 'true' to an LDAP-compatible 'TRUE'. All other
       
   171      * other values are converted to an LDAP-compatible 'FALSE'.
       
   172      *
       
   173      * @param	boolean|integer|string		$value	The boolean value to encode
       
   174      * @return	string
       
   175      */
       
   176     public static function toLdapBoolean($value)
       
   177     {
       
   178         $return = 'FALSE';
       
   179         if (!is_scalar($value)) {
       
   180             return $return;
       
   181         }
       
   182         if (true === $value || 'true' === strtolower($value) || 1 === $value) {
       
   183             $return = 'TRUE';
       
   184         }
       
   185         return $return;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Serialize any value for storage in LDAP
       
   190      *
       
   191      * @param	mixed		$value	The value to serialize
       
   192      * @return	string
       
   193      */
       
   194     public static function toLdapSerialize($value)
       
   195     {
       
   196         return serialize($value);
       
   197     }
       
   198 
       
   199     /**
       
   200      * Convert an LDAP-compatible value to a corresponding PHP-value.
       
   201      *
       
   202      * By setting the <var>$type</var>-parameter the conversion of a certain
       
   203      * type can be forced
       
   204      * .
       
   205      * @param	string	$value 			The value to convert
       
   206      * @param	int		$ytpe  			The conversion type to use
       
   207      * @param	boolean	$dateTimeAsUtc	Return DateTime values in UTC timezone
       
   208      * @return	mixed
       
   209      * @throws	Zend_Ldap_Converter_Exception
       
   210      */
       
   211     public static function fromLdap($value, $type = self::STANDARD, $dateTimeAsUtc = true)
       
   212     {
       
   213         switch ($type) {
       
   214             case self::BOOLEAN:
       
   215                 return self::fromldapBoolean($value);
       
   216                 break;
       
   217             case self::GENERALIZED_TIME:
       
   218                 return self::fromLdapDateTime($value);
       
   219                 break;
       
   220             default:
       
   221                 if (is_numeric($value)) {
       
   222                     return (float)$value;
       
   223                 } else if ('TRUE' === $value || 'FALSE' === $value) {
       
   224                     return self::fromLdapBoolean($value);
       
   225                 }
       
   226                 if (preg_match('/^\d{4}[\d\+\-Z\.]*$/', $value)) {
       
   227                     return self::fromLdapDateTime($value, $dateTimeAsUtc);
       
   228                 }
       
   229                 try {
       
   230                     return self::fromLdapUnserialize($value);
       
   231                 } catch (UnexpectedValueException $e) { }
       
   232                 break;
       
   233         }
       
   234         return $value;
       
   235     }
       
   236 
       
   237     /**
       
   238      * Convert an LDAP-Generalized-Time-entry into a DateTime-Object
       
   239      *
       
   240      * CAVEAT: The DateTime-Object returned will alwasy be set to UTC-Timezone.
       
   241      *
       
   242      * @param	string		$date	The generalized-Time
       
   243      * @param	boolean		$asUtc	Return the DateTime with UTC timezone
       
   244      * @return	DateTime
       
   245      * @throws	InvalidArgumentException if a non-parseable-format is given
       
   246      */
       
   247     public static function fromLdapDateTime($date, $asUtc = true)
       
   248     {
       
   249         $datepart = array ();
       
   250         if (!preg_match('/^(\d{4})/', $date, $datepart) ) {
       
   251             throw new InvalidArgumentException('Invalid date format found');
       
   252         }
       
   253 
       
   254         if ($datepart[1] < 4) {
       
   255             throw new InvalidArgumentException('Invalid date format found (too short)');
       
   256         }
       
   257 
       
   258         $time = array (
       
   259             // The year is mandatory!
       
   260             'year'   => $datepart[1],
       
   261             'month'  => 1,
       
   262             'day'    => 1,
       
   263             'hour'   => 0,
       
   264             'minute' => 0,
       
   265             'second' => 0,
       
   266             'offdir' => '+',
       
   267             'offsethours' => 0,
       
   268 			'offsetminutes' => 0
       
   269         );
       
   270 
       
   271         $length = strlen($date);
       
   272 
       
   273         // Check for month.
       
   274         if ($length >= 6) {
       
   275             $month = substr($date, 4, 2);
       
   276             if ($month < 1 || $month > 12) {
       
   277                 throw new InvalidArgumentException('Invalid date format found (invalid month)');
       
   278             }
       
   279             $time['month'] = $month;
       
   280         }
       
   281 
       
   282         // Check for day
       
   283         if ($length >= 8) {
       
   284             $day = substr($date, 6, 2);
       
   285             if ($day < 1 || $day > 31) {
       
   286                 throw new InvalidArgumentException('Invalid date format found (invalid day)');
       
   287             }
       
   288             $time['day'] = $day;
       
   289         }
       
   290 
       
   291         // Check for Hour
       
   292         if ($length >= 10) {
       
   293             $hour = substr($date, 8, 2);
       
   294             if ($hour < 0 || $hour > 23) {
       
   295                 throw new InvalidArgumentException('Invalid date format found (invalid hour)');
       
   296             }
       
   297             $time['hour'] = $hour;
       
   298         }
       
   299 
       
   300         // Check for minute
       
   301         if ($length >= 12) {
       
   302             $minute = substr($date, 10, 2);
       
   303             if ($minute < 0 || $minute > 59) {
       
   304                 throw new InvalidArgumentException('Invalid date format found (invalid minute)');
       
   305             }
       
   306             $time['minute'] = $minute;
       
   307         }
       
   308 
       
   309         // Check for seconds
       
   310         if ($length >= 14) {
       
   311             $second = substr($date, 12, 2);
       
   312             if ($second < 0 || $second > 59) {
       
   313                 throw new InvalidArgumentException('Invalid date format found (invalid second)');
       
   314             }
       
   315             $time['second'] = $second;
       
   316         }
       
   317 
       
   318         // Set Offset
       
   319         $offsetRegEx = '/([Z\-\+])(\d{2}\'?){0,1}(\d{2}\'?){0,1}$/';
       
   320         $off         = array ();
       
   321         if (preg_match($offsetRegEx, $date, $off)) {
       
   322             $offset = $off[1];
       
   323             if ($offset == '+' || $offset == '-') {
       
   324                 $time['offdir'] = $offset;
       
   325                 // we have an offset, so lets calculate it.
       
   326                 if (isset($off[2])) {
       
   327                     $offsetHours = substr($off[2], 0, 2);
       
   328                     if ($offsetHours < 0 || $offsetHours > 12) {
       
   329                         throw new InvalidArgumentException('Invalid date format found (invalid offset hour)');
       
   330                     }
       
   331                     $time['offsethours'] = $offsetHours;
       
   332                 }
       
   333                 if (isset($off[3])) {
       
   334                     $offsetMinutes = substr($off[3], 0, 2);
       
   335                     if ($offsetMinutes < 0 || $offsetMinutes > 59) {
       
   336                         throw new InvalidArgumentException('Invalid date format found (invalid offset minute)');
       
   337                     }
       
   338                     $time['offsetminutes'] = $offsetMinutes;
       
   339                 }
       
   340             }
       
   341         }
       
   342 
       
   343         // Raw-Data is present, so lets create a DateTime-Object from it.
       
   344         $offset = $time['offdir']
       
   345                 . str_pad($time['offsethours'],2,'0',STR_PAD_LEFT)
       
   346                 . str_pad($time['offsetminutes'],2,'0',STR_PAD_LEFT);
       
   347         $timestring = $time['year'] . '-'
       
   348                     . str_pad($time['month'], 2, '0', STR_PAD_LEFT) . '-'
       
   349                     . str_pad($time['day'], 2, '0', STR_PAD_LEFT) . ' '
       
   350                     . str_pad($time['hour'], 2, '0', STR_PAD_LEFT) . ':'
       
   351                     . str_pad($time['minute'], 2, '0', STR_PAD_LEFT) . ':'
       
   352                     . str_pad($time['second'], 2, '0', STR_PAD_LEFT)
       
   353                     . $time['offdir']
       
   354                     . str_pad($time['offsethours'], 2, '0', STR_PAD_LEFT)
       
   355                     . str_pad($time['offsetminutes'], 2, '0', STR_PAD_LEFT);
       
   356         $date = new DateTime($timestring);
       
   357         if ($asUtc) {
       
   358             $date->setTimezone(new DateTimeZone('UTC'));
       
   359         }
       
   360         return $date;
       
   361     }
       
   362 
       
   363     /**
       
   364      * Convert an LDAP-compatible boolean value into a PHP-compatible one
       
   365      *
       
   366      * @param	string		$value		The value to convert
       
   367      * @return	boolean
       
   368      * @throws	InvalidArgumentException
       
   369      */
       
   370     public static function fromLdapBoolean($value)
       
   371     {
       
   372         if ( 'TRUE' === $value ) {
       
   373             return true;
       
   374         } else if ( 'FALSE' === $value ) {
       
   375             return false;
       
   376         } else {
       
   377             throw new InvalidArgumentException('The given value is not a boolean value');
       
   378         }
       
   379     }
       
   380 
       
   381     /**
       
   382      * Unserialize a serialized value to return the corresponding object
       
   383      *
       
   384      * @param	string		$value	The value to convert
       
   385      * @return	mixed
       
   386      * @throws	UnexpectedValueException
       
   387      */
       
   388     public static function fromLdapUnserialize($value)
       
   389     {
       
   390         $v = @unserialize($value);
       
   391         if (false===$v && $value != 'b:0;') {
       
   392             throw new UnexpectedValueException('The given value could not be unserialized');
       
   393         }
       
   394         return $v;
       
   395     }
       
   396 }