Changeset 4844 in subversion
- Timestamp:
- Jun 9, 2011 3:43:22 PM (2 years ago)
- Location:
- trunk/roundcubemail
- Files:
-
- 3 edited
-
CHANGELOG (modified) (1 diff)
-
config/main.inc.php.dist (modified) (1 diff)
-
program/include/rcube_ldap.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail/CHANGELOG
r4840 r4844 2 2 =========================== 3 3 4 - Implement LDAPv3 Virtual List View (VLV) for paged results listing 4 5 - Use 'address_template' config option when adding a new address block (#1487944) 5 6 - Added addressbook advanced search -
trunk/roundcubemail/config/main.inc.php.dist
r4823 r4844 535 535 'filter' => '(objectClass=inetOrgPerson)', // used for basic listing (if not empty) and will be &'d with search queries. example: status=act 536 536 'fuzzy_search' => true, // server allows wildcard search 537 'vlv' => false, // Enable Virtual List View to mor efficiently fetch paginated data (if server supports it) 537 538 'sizelimit' => '0', // Enables you to limit the count of entries fetched. Setting this to 0 means no limit. 538 539 'timelimit' => '0', // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit. -
trunk/roundcubemail/program/include/rcube_ldap.php
r4834 r4844 55 55 private $group_members = array(); 56 56 57 private $vlv_active = false; 58 private $vlv_count = 0; 59 57 60 58 61 /** … … 418 421 if ($this->ldap_result && $this->result->count > 0) 419 422 { 420 if ($this->sort_col && $this->prop['scope'] !== 'base' )423 if ($this->sort_col && $this->prop['scope'] !== 'base' && !$this->vlv_active) 421 424 ldap_sort($this->conn, $this->ldap_result, $this->sort_col); 422 425 423 $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; 426 $start_row = $this->vlv_active ? 0 : $this->result->first; 427 $start_row = $subset < 0 ? $start_row + $this->page_size + $subset : $start_row; 424 428 $last_row = $this->result->first + $this->page_size; 425 429 $last_row = $subset != 0 ? $start_row + abs($subset) : $last_row; … … 548 552 $count = 0; 549 553 if ($this->conn && $this->ldap_result) { 550 $count = ldap_count_entries($this->conn, $this->ldap_result);554 $count = $this->vlv_active ? $this->vlv_count : ldap_count_entries($this->conn, $this->ldap_result); 551 555 } // end if 552 556 elseif ($this->conn) { … … 556 560 $this->filter = $this->prop['filter']; 557 561 } // end if 558 $this->_exec_search( );562 $this->_exec_search(true); 559 563 if ($this->ldap_result) { 560 564 $count = ldap_count_entries($this->conn, $this->ldap_result); … … 857 861 * @access private 858 862 */ 859 private function _exec_search( )863 private function _exec_search($all = false) 860 864 { 861 865 if ($this->ready) … … 865 869 866 870 $this->_debug("C: Search [".$filter."]"); 871 872 // when using VLV, we need to issue listing command first in order to get the full count 873 if (!$all && $function != 'ldap_read' && $this->prop['vlv']) { 874 $this->_exec_search(true); 875 $this->vlv_count = ldap_count_entries($this->conn, $this->ldap_result); 876 $this->vlv_active = $this->_vlv_set_controls(); 877 } 867 878 868 879 if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter, … … 879 890 880 891 return false; 892 } 893 894 /** 895 * Set server controls for Virtual List View (paginated listing) 896 */ 897 private function _vlv_set_controls() 898 { 899 $sort_ctrl = array('oid' => "1.2.840.113556.1.4.473", 'value' => $this->_sort_ber_encode(array($this->sort_col))); 900 $vlv_ctrl = array('oid' => "2.16.840.1.113730.3.4.9", 'value' => $this->_vlv_ber_encode(($offset = ($this->list_page-1) * $this->page_size + 1), $this->page_size), 'iscritical' => true); 901 902 //$this->_debug("C: set controls sort=" . join(' ', unpack('H'.(strlen($sort_ctrl['value'])*2), $sort_ctrl['value'])) . " ({$this->sort_col});" 903 // . " vlv=" . join(' ', (unpack('H'.(strlen($vlv_ctrl['value'])*2), $vlv_ctrl['value']))) . " ($offset)"); 904 905 if (!ldap_set_option($this->conn, LDAP_OPT_SERVER_CONTROLS, array($sort_ctrl, $vlv_ctrl))) { 906 $this->_debug("S: ".ldap_error($this->conn)); 907 $this->set_error(self::ERROR_SEARCH, 'vlvnotsupported'); 908 return false; 909 } 910 911 return true; 881 912 } 882 913 … … 1229 1260 return $groups; 1230 1261 } 1262 1263 1264 /** 1265 * Generate BER encoded string for Virtual List View option 1266 * 1267 * @param integer List offset (first record) 1268 * @param integer Records per page 1269 * @return string BER encoded option value 1270 */ 1271 private function _vlv_ber_encode($offset, $rpp) 1272 { 1273 # this string is ber-encoded, php will prefix this value with: 1274 # 04 (octet string) and 10 (length of 16 bytes) 1275 # the code behind this string is broken down as follows: 1276 # 30 = ber sequence with a length of 0e (14) bytes following 1277 # 20 = type integer (in two's complement form) with 2 bytes following (beforeCount): 01 00 (ie 0) 1278 # 20 = type integer (in two's complement form) with 2 bytes following (afterCount): 01 18 (ie 25-1=24) 1279 # a0 = type context-specific/constructed with a length of 06 (6) bytes following 1280 # 20 = type integer with 2 bytes following (offset): 01 01 (ie 1) 1281 # 20 = type integer with 2 bytes following (contentCount): 01 00 1282 # the following info was taken from the ISO/IEC 8825-1:2003 x.690 standard re: the 1283 # encoding of integer values (note: these values are in 1284 # two-complement form so since offset will never be negative bit 8 of the 1285 # leftmost octet should never by set to 1): 1286 # 8.3.2: If the contents octets of an integer value encoding consist 1287 # of more than one octet, then the bits of the first octet (rightmost) and bit 8 1288 # of the second (to the left of first octet) octet: 1289 # a) shall not all be ones; and 1290 # b) shall not all be zero 1291 1292 # construct the string from right to left 1293 $str = "020100"; # contentCount 1294 1295 $ber_val = self::_ber_encode_int($offset); // returns encoded integer value in hex format 1296 1297 // calculate octet length of $ber_val 1298 $str = self::_ber_addseq($ber_val, '02') . $str; 1299 1300 // now compute length over $str 1301 $str = self::_ber_addseq($str, 'a0'); 1302 1303 // now tack on records per page 1304 $str = sprintf("0201000201%02x", min(255, $rpp)-1) . $str; 1305 1306 // now tack on sequence identifier and length 1307 $str = self::_ber_addseq($str, '30'); 1308 1309 return pack('H'.strlen($str), $str); 1310 } 1311 1312 1313 /** 1314 * create ber encoding for sort control 1315 * 1316 * @pararm array List of cols to sort by 1317 * @return string BER encoded option value 1318 */ 1319 private function _sort_ber_encode($sortcols) 1320 { 1321 $str = ''; 1322 foreach (array_reverse((array)$sortcols) as $col) { 1323 $ber_val = self::_string2hex($col); 1324 1325 # 30 = ber sequence with a length of octet value 1326 # 04 = octet string with a length of the ascii value 1327 $oct = self::_ber_addseq($ber_val, '04'); 1328 $str = self::_ber_addseq($oct, '30') . $str; 1329 } 1330 1331 // now tack on sequence identifier and length 1332 $str = self::_ber_addseq($str, '30'); 1333 1334 return pack('H'.strlen($str), $str); 1335 } 1336 1337 /** 1338 * Add BER sequence with correct length and the given identifier 1339 */ 1340 private static function _ber_addseq($str, $identifier) 1341 { 1342 $len = sprintf("%x", strlen($str)/2); 1343 if (strlen($len) % 2 != 0) 1344 $len = '0'.$len; 1345 1346 return $identifier . $len . $str; 1347 } 1348 1349 /** 1350 * Returns BER encoded integer value in hex format 1351 */ 1352 private static function _ber_encode_int($offset) 1353 { 1354 $val = sprintf("%x", $offset); 1355 $prefix = ''; 1356 1357 // check if bit 8 of high byte is 1 1358 if (preg_match('/^[89abcdef]/', $val)) 1359 $prefix = '00'; 1360 1361 if (strlen($val)%2 != 0) 1362 $prefix .= '0'; 1363 1364 return $prefix . $val; 1365 } 1366 1367 /** 1368 * Returns ascii string encoded in hex 1369 */ 1370 private static function _string2hex($str) { 1371 $hex = ''; 1372 for ($i=0; $i < strlen($str); $i++) 1373 $hex .= dechex(ord($str[$i])); 1374 return $hex; 1375 } 1376 1231 1377 }
Note: See TracChangeset
for help on using the changeset viewer.
