web/lib/Zend/Ldap/Ldif/Encoder.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  * @subpackage Ldif
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: Encoder.php 21005 2010-02-09 13:16:26Z sgehrig $
       
    21  */
       
    22 
       
    23 /**
       
    24  * Zend_Ldap_Ldif_Encoder provides methods to encode and decode LDAP data into/from LDIF.
       
    25  *
       
    26  * @category   Zend
       
    27  * @package    Zend_Ldap
       
    28  * @subpackage Ldif
       
    29  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    30  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    31  */
       
    32 class Zend_Ldap_Ldif_Encoder
       
    33 {
       
    34     /**
       
    35      * Additional options used during encoding
       
    36      *
       
    37      * @var array
       
    38      */
       
    39     protected $_options = array(
       
    40         'sort'    => true,
       
    41         'version' => 1,
       
    42         'wrap'    => 78
       
    43     );
       
    44 
       
    45     /**
       
    46      * @var boolean
       
    47      */
       
    48     protected $_versionWritten = false;
       
    49 
       
    50     /**
       
    51      * Constructor.
       
    52      *
       
    53      * @param  array $options Additional options used during encoding
       
    54      * @return void
       
    55      */
       
    56     protected function __construct(array $options = array())
       
    57     {
       
    58         $this->_options = array_merge($this->_options, $options);
       
    59     }
       
    60 
       
    61     /**
       
    62      * Decodes the string $string into an array of LDIF items
       
    63      *
       
    64      * @param  string $string
       
    65      * @return array
       
    66      */
       
    67     public static function decode($string)
       
    68     {
       
    69         $encoder = new self(array());
       
    70         return $encoder->_decode($string);
       
    71     }
       
    72 
       
    73     /**
       
    74      * Decodes the string $string into an array of LDIF items
       
    75      *
       
    76      * @param  string $string
       
    77      * @return array
       
    78      */
       
    79     protected function _decode($string)
       
    80     {
       
    81         $items = array();
       
    82         $item = array();
       
    83         $last = null;
       
    84         foreach (explode("\n", $string) as $line) {
       
    85             $line = rtrim($line, "\x09\x0A\x0D\x00\x0B");
       
    86             $matches = array();
       
    87             if (substr($line, 0, 1) === ' ' && $last !== null) {
       
    88                 $last[2] .= substr($line, 1);
       
    89             } else if (substr($line, 0, 1) === '#') {
       
    90                 continue;
       
    91             } else if (preg_match('/^([a-z0-9;-]+)(:[:<]?\s*)([^:<]*)$/i', $line, $matches)) {
       
    92                 $name = strtolower($matches[1]);
       
    93                 $type = trim($matches[2]);
       
    94                 $value = $matches[3];
       
    95                 if ($last !== null) {
       
    96                     $this->_pushAttribute($last, $item);
       
    97                 }
       
    98                 if ($name === 'version') {
       
    99                     continue;
       
   100                 } else if (count($item) > 0 && $name === 'dn') {
       
   101                     $items[] = $item;
       
   102                     $item = array();
       
   103                     $last = null;
       
   104                 }
       
   105                 $last = array($name, $type, $value);
       
   106             } else if (trim($line) === '') {
       
   107                 continue;
       
   108             }
       
   109         }
       
   110         if ($last !== null) {
       
   111             $this->_pushAttribute($last, $item);
       
   112         }
       
   113         $items[] = $item;
       
   114         return (count($items)>1) ? $items : $items[0];
       
   115     }
       
   116 
       
   117     /**
       
   118      * Pushes a decoded attribute to the stack
       
   119      *
       
   120      * @param array $attribute
       
   121      * @param array $entry
       
   122      */
       
   123     protected function _pushAttribute(array $attribute, array &$entry)
       
   124     {
       
   125         $name = $attribute[0];
       
   126         $type = $attribute[1];
       
   127         $value = $attribute[2];
       
   128         if ($type === '::') {
       
   129             $value = base64_decode($value);
       
   130         }
       
   131         if ($name === 'dn') {
       
   132             $entry[$name] = $value;
       
   133         } else if (isset($entry[$name]) && $value !== '') {
       
   134             $entry[$name][] = $value;
       
   135         } else {
       
   136             $entry[$name] = ($value !== '') ? array($value) : array();
       
   137         }
       
   138     }
       
   139 
       
   140     /**
       
   141      * Encode $value into a LDIF representation
       
   142      *
       
   143      * @param  mixed $value   The value to be encoded
       
   144      * @param  array $options Additional options used during encoding
       
   145      * @return string The encoded value
       
   146      */
       
   147     public static function encode($value, array $options = array())
       
   148     {
       
   149         $encoder = new self($options);
       
   150         return $encoder->_encode($value);
       
   151     }
       
   152 
       
   153     /**
       
   154      * Recursive driver which determines the type of value to be encoded
       
   155      * and then dispatches to the appropriate method.
       
   156      *
       
   157      * @param  mixed $value The value to be encoded
       
   158      * @return string Encoded value
       
   159      */
       
   160     protected function _encode($value)
       
   161     {
       
   162         if (is_scalar($value)) {
       
   163             return $this->_encodeString($value);
       
   164         } else if (is_array($value)) {
       
   165             return $this->_encodeAttributes($value);
       
   166         } else if ($value instanceof Zend_Ldap_Node) {
       
   167             return $value->toLdif($this->_options);
       
   168         }
       
   169         return null;
       
   170     }
       
   171 
       
   172     /**
       
   173      * Encodes $string according to RFC2849
       
   174      *
       
   175      * @link http://www.faqs.org/rfcs/rfc2849.html
       
   176      *
       
   177      * @param  string $string
       
   178      * @param  boolen $base64
       
   179      * @return string
       
   180      */
       
   181     protected function _encodeString($string, &$base64 = null)
       
   182     {
       
   183         $string = (string)$string;
       
   184         if (!is_numeric($string) && empty($string)) {
       
   185             return '';
       
   186         }
       
   187 
       
   188         /*
       
   189          * SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
       
   190          *                  %x21-39 / %x3B / %x3D-7F
       
   191          *                ; any value <= 127 except NUL, LF, CR,
       
   192          *                ; SPACE, colon (":", ASCII 58 decimal)
       
   193          *                ; and less-than ("<" , ASCII 60 decimal)
       
   194          *
       
   195          */
       
   196         $unsafe_init_char = array(0, 10, 13, 32, 58, 60);
       
   197         /*
       
   198          * SAFE-CHAR      = %x01-09 / %x0B-0C / %x0E-7F
       
   199          *                ; any value <= 127 decimal except NUL, LF,
       
   200          *                ; and CR
       
   201          */
       
   202         $unsafe_char      = array(0, 10, 13);
       
   203 
       
   204         $base64 = false;
       
   205         for ($i = 0; $i < strlen($string); $i++) {
       
   206             $char = ord(substr($string, $i, 1));
       
   207             if ($char >= 127) {
       
   208                 $base64 = true;
       
   209                 break;
       
   210             } else if ($i === 0 && in_array($char, $unsafe_init_char)) {
       
   211                 $base64 = true;
       
   212                 break;
       
   213             } else if (in_array($char, $unsafe_char)) {
       
   214                 $base64 = true;
       
   215                 break;
       
   216             }
       
   217         }
       
   218         // Test for ending space
       
   219         if (substr($string, -1) == ' ') {
       
   220             $base64 = true;
       
   221         }
       
   222 
       
   223         if ($base64 === true) {
       
   224             $string = base64_encode($string);
       
   225         }
       
   226 
       
   227         return $string;
       
   228     }
       
   229 
       
   230     /**
       
   231      * Encodes an attribute with $name and $value according to RFC2849
       
   232      *
       
   233      * @link http://www.faqs.org/rfcs/rfc2849.html
       
   234      *
       
   235      * @param  string       $name
       
   236      * @param  array|string $value
       
   237      * @return string
       
   238      */
       
   239     protected function _encodeAttribute($name, $value)
       
   240     {
       
   241         if (!is_array($value)) {
       
   242             $value = array($value);
       
   243         }
       
   244 
       
   245         $output = '';
       
   246 
       
   247         if (count($value) < 1) {
       
   248             return $name . ': ';
       
   249         }
       
   250 
       
   251         foreach ($value as $v) {
       
   252             $base64 = null;
       
   253             $v = $this->_encodeString($v, $base64);
       
   254             $attribute = $name . ':';
       
   255             if ($base64 === true) {
       
   256                 $attribute .= ': ' . $v;
       
   257             } else {
       
   258                 $attribute .= ' ' . $v;
       
   259             }
       
   260             if (isset($this->_options['wrap']) && strlen($attribute) > $this->_options['wrap']) {
       
   261                 $attribute = trim(chunk_split($attribute, $this->_options['wrap'], PHP_EOL . ' '));
       
   262             }
       
   263             $output .= $attribute . PHP_EOL;
       
   264         }
       
   265         return trim($output, PHP_EOL);
       
   266     }
       
   267 
       
   268     /**
       
   269      * Encodes a collection of attributes according to RFC2849
       
   270      *
       
   271      * @link http://www.faqs.org/rfcs/rfc2849.html
       
   272      *
       
   273      * @param  array $attributes
       
   274      * @return string
       
   275      */
       
   276     protected function _encodeAttributes(array $attributes)
       
   277     {
       
   278         $string = '';
       
   279         $attributes = array_change_key_case($attributes, CASE_LOWER);
       
   280         if (!$this->_versionWritten && array_key_exists('dn', $attributes) && isset($this->_options['version'])
       
   281                 && array_key_exists('objectclass', $attributes)) {
       
   282             $string .= sprintf('version: %d', $this->_options['version']) . PHP_EOL;
       
   283             $this->_versionWritten = true;
       
   284         }
       
   285 
       
   286         if (isset($this->_options['sort']) && $this->_options['sort'] === true) {
       
   287             ksort($attributes, SORT_STRING);
       
   288             if (array_key_exists('objectclass', $attributes)) {
       
   289                 $oc = $attributes['objectclass'];
       
   290                 unset($attributes['objectclass']);
       
   291                 $attributes = array_merge(array('objectclass' => $oc), $attributes);
       
   292             }
       
   293             if (array_key_exists('dn', $attributes)) {
       
   294                 $dn = $attributes['dn'];
       
   295                 unset($attributes['dn']);
       
   296                 $attributes = array_merge(array('dn' => $dn), $attributes);
       
   297             }
       
   298         }
       
   299         foreach ($attributes as $key => $value) {
       
   300             $string .= $this->_encodeAttribute($key, $value) . PHP_EOL;
       
   301         }
       
   302         return trim($string, PHP_EOL);
       
   303     }
       
   304 }