PHP

2009-09-24 5 views
12

के साथ एलडीएपी में सभी उपयोगकर्ताओं का आकलन करें मैं एक दैनिक क्रॉन के रूप में चलने वाली एक PHP स्क्रिप्ट बनाना चाहता हूं। मैं जो करना चाहता हूं वह सक्रिय निर्देशिका के भीतर सभी उपयोगकर्ताओं के माध्यम से गणना करता है, प्रत्येक प्रविष्टि से कुछ फ़ील्ड निकालें, और इस जानकारी का उपयोग MySQL डेटाबेस के भीतर फ़ील्ड को अपडेट करने के लिए करें।PHP

असल में मैं जो करना चाहता हूं वह सक्रिय निर्देशिका और एक MySQL तालिका के बीच कुछ उपयोगकर्ता जानकारी को सिंक करना है।

मेरी समस्या यह है कि सक्रिय निर्देशिका सर्वर पर sizelimit अक्सर खोज परिणामों के 1000 प्रविष्टियों पर सेट किया जाता है। मैंने आशा की थी कि php फ़ंक्शन "ldap_next_entry" एक समय में केवल एक प्रविष्टि प्राप्त करके ही प्राप्त होगा, लेकिन इससे पहले कि आप "ldap_next_entry" को कॉल कर सकें, आपको पहले "ldap_search" को कॉल करना होगा, जो SizeLimit को त्रुटि से अधिक ट्रिगर कर सकता है।

क्या सर्वर से sizelimit को हटाने के अलावा कोई तरीका है? क्या मैं किसी भी तरह के परिणामों के "पेज" प्राप्त कर सकता हूं?

बीटीडब्ल्यू - मैं वर्तमान में किसी तीसरे पक्ष के पुस्तकालयों या कोड का उपयोग नहीं कर रहा हूं। बस PHPs ldap विधियों। हालांकि, मैं लाइब्रेरी का उपयोग करने के लिए निश्चित रूप से खुला हूं अगर इससे मदद मिलेगी।

उत्तर

15

मुझे Zend_Ldap के विकास के दौरान एक ही समस्या से मारा गया है ज़ेंड फ्रेमवर्क के लिए। मैं यह समझाने की कोशिश करूंगा कि वास्तविक समस्या क्या है, लेकिन इसे कम करने के लिए: PHP 5.4 तक, एक असीमित PHP (ext/ldap) संस्करण के साथ एक सक्रिय निर्देशिका से पेज किए गए परिणामों का उपयोग करना संभव नहीं था क्योंकि वास्तव में सीमाएं विस्तार

आइए पूरी चीज़ को सुलझाने का प्रयास करें ... Microsoft सक्रिय निर्देशिका सर्वर-साइड परिणाम पेजिंग को पूरा करने के लिए एक तथाकथित सर्वर नियंत्रण का उपयोग करती है। यह नियंत्रण RFC 2696 "LDAP Control Extension for Simple Paged Results Manipulation" में वर्णित है।

ext/php क्रमशः अपने ldap_set_option() और LDAP_OPT_SERVER_CONTROLS और LDAP_OPT_CLIENT_CONTROLS विकल्प के माध्यम से LDAP नियंत्रण विस्तार में कोई प्रदान करता है। पेज किए गए नियंत्रण को सेट करने के लिए आपको नियंत्रण-ओआईडी की आवश्यकता होती है, जो 1.2.840.113556.1.4.319 है, और हमें यह जानने की आवश्यकता है कि नियंत्रण-मूल्य को कैसे एन्कोड किया जाए (यह RFC में वर्णित है)।

$pageSize = 100; 
$pageControl = array(
    'oid'  => '1.2.840.113556.1.4.319', // the control-oid 
    'iscritical' => true, // the operation should fail if the server is not able to support this control 
    'value'  => sprintf ("%c%c%c%c%c%c%c", 48, 5, 2, 1, $pageSize, 4, 0) // the required BER-encoded control-value 
); 
:

realSearchControlValue ::= SEQUENCE { 
     size   INTEGER (0..maxInt), 
           -- requested page size from client 
           -- result set size estimate from server 
     cookie   OCTET STRING 
} 

तो हम LDAP क्वेरी को क्रियान्वित करने से पहले उपयुक्त सर्वर नियंत्रण सेट कर सकते हैं: मूल्य संख्या एन्कोड (RFC से नकल) निम्न क्रम के संस्करण लपेटकर ओकटेट स्ट्रिंग है

यह हमें एलडीएपी/एडी सर्वर पर एक पेजेड क्वेरी भेजने की अनुमति देता है। लेकिन हम कैसे जानते हैं कि अनुसरण करने के लिए और अधिक पृष्ठ हैं और हम कैसे निर्दिष्ट करते हैं कि किस नियंत्रण-मूल्य के साथ हमें अपनी अगली क्वेरी भेजनी है?

यह वह जगह है जहां हम अटक रहे हैं ... सर्वर एक परिणाम सेट के साथ प्रतिक्रिया करता है जिसमें आवश्यक पेजिंग जानकारी शामिल है लेकिन PHP में परिणाम सेट से बिल्कुल इस जानकारी को पुनर्प्राप्त करने के लिए कोई तरीका नहीं है। PHP एलडीएपी एपीआई फ़ंक्शन ldap_parse_result() के लिए एक रैपर प्रदान करता है लेकिन आवश्यक अंतिम पैरामीटर serverctrlsp PHP फ़ंक्शन से अवगत नहीं है, इसलिए आवश्यक जानकारी पुनर्प्राप्त करने का कोई तरीका नहीं है। एक bug report इस मुद्दे के लिए दायर किया गया है लेकिन ldap_parse_result() समारोह आवश्यक पैरामीटर प्रदान की तो 2005 के बाद से कोई जवाब नहीं आया है, पृष्ठांकित परिणामों का उपयोग की तरह

$l = ldap_connect('somehost.mydomain.com'); 
$pageSize = 100; 
$pageControl = array(
    'oid'  => '1.2.840.113556.1.4.319', 
    'iscritical' => true, 
    'value'  => sprintf ("%c%c%c%c%c%c%c", 48, 5, 2, 1, $pageSize, 4, 0) 

); 
$controls = array($pageControl); 

ldap_set_option($l, LDAP_OPT_PROTOCOL_VERSION, 3); 
ldap_bind($l, 'CN=bind-user,OU=my-users,DC=mydomain,DC=com', 'bind-user-password'); 

$continue = true; 
while ($continue) { 
    ldap_set_option($l, LDAP_OPT_SERVER_CONTROLS, $controls); 
    $sr = ldap_search($l, 'OU=some-ou,DC=mydomain,DC=com', 'cn=*', array('sAMAccountName'), null, null, null, null); 
    ldap_parse_result ($l, $sr, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls); // (*) 
    if (isset($serverctrls)) { 
     foreach ($serverctrls as $i) { 
      if ($i["oid"] == '1.2.840.113556.1.4.319') { 
        $i["value"]{8} = chr($pageSize); 
        $i["iscritical"] = true; 
        $controls  = array($i); 
        break; 
      } 
     } 
    } 

    $info = ldap_get_entries($l, $sr); 
    if ($info["count"] < $pageSize) { 
     $continue = false; 
    } 

    for ($entry = ldap_first_entry($l, $sr); $entry != false; $entry = ldap_next_entry($l, $entry)) { 
     $dn = ldap_get_dn($l, $entry); 
    } 
} 

काम करेगा जैसा कि आप देख कोड (*) की एक पंक्ति है जो पूरी चीज बेकार है। मेरे रास्ते पर हालांकि इस विषय पर छेड़छाड़ की जानकारी मुझे आईनाकी एरेनाज़ा द्वारा PHP 4.3.10 ext/ldap के खिलाफ एक पैच मिला लेकिन मैंने कोशिश नहीं की और न ही मुझे पता है कि पैच को PHP5 ext/ldap पर लागू किया जा सकता है या नहीं। पैच ldap_parse_result() फैली पीएचपी करने के लिए 7 वीं पैरामीटर बेनकाब करने के लिए:

--- ldap.c 2004-06-01 23:05:33.000000000 +0200 
+++ /usr/src/php4/php4-4.3.10/ext/ldap/ldap.c 2005-09-03 17:02:03.000000000 +0200 
@@ -74,7 +74,7 @@ 
ZEND_DECLARE_MODULE_GLOBALS(ldap) 

static unsigned char third_argument_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE }; 
-static unsigned char arg3to6of6_force_ref[] = { 6, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE }; 
+static unsigned char arg3to7of7_force_ref[] = { 7, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE }; 

static int le_link, le_result, le_result_entry, le_ber_entry; 

@@ -124,7 +124,7 @@ 
#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP 
    PHP_FE(ldap_get_option, third_argument_force_ref) 
    PHP_FE(ldap_set_option,  NULL) 
- PHP_FE(ldap_parse_result, arg3to6of6_force_ref) 
+ PHP_FE(ldap_parse_result, arg3to7of7_force_ref) 
    PHP_FE(ldap_first_reference,  NULL) 
    PHP_FE(ldap_next_reference,  NULL) 
#ifdef HAVE_LDAP_PARSE_REFERENCE 
@@ -1775,14 +1775,15 @@ 
    Extract information from result */ 
PHP_FUNCTION(ldap_parse_result) 
{ 
- pval **link, **result, **errcode, **matcheddn, **errmsg, **referrals; 
+ pval **link, **result, **errcode, **matcheddn, **errmsg, **referrals, **serverctrls; 
    ldap_linkdata *ld; 
    LDAPMessage *ldap_result; 
+ LDAPControl **lserverctrls, **ctrlp, *ctrl; 
    char **lreferrals, **refp; 
    char *lmatcheddn, *lerrmsg; 
    int rc, lerrcode, myargcount = ZEND_NUM_ARGS(); 

- if (myargcount 6 || zend_get_parameters_ex(myargcount, &link, &result, &errcode, &matcheddn, &errmsg, &referrals) == FAILURE) { 
+ if (myargcount 7 || zend_get_parameters_ex(myargcount, &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) == FAILURE) { 
    WRONG_PARAM_COUNT; 
    } 

@@ -1793,7 +1794,7 @@ 
    myargcount > 3 ? &lmatcheddn : NULL, 
    myargcount > 4 ? &lerrmsg : NULL, 
    myargcount > 5 ? &lreferrals : NULL, 
- NULL /* &serverctrls */, 
+ myargcount > 6 ? &lserverctrls : NULL, 
    0); 
    if (rc != LDAP_SUCCESS) { 
    php_error(E_WARNING, "%s(): Unable to parse result: %s", get_active_function_name(TSRMLS_C), ldap_err2string(rc)); 
@@ -1805,6 +1806,29 @@ 

    /* Reverse -> fall through */ 
    switch(myargcount) { 
+ case 7 : 
+ zval_dtor(*serverctrls); 
+ 
+ if (lserverctrls != NULL) { 
+ array_init(*serverctrls); 
+ ctrlp = lserverctrls; 
+ 
+ while (*ctrlp != NULL) { 
+  zval *ctrl_array; 
+ 
+  ctrl = *ctrlp; 
+  MAKE_STD_ZVAL(ctrl_array); 
+  array_init(ctrl_array); 
+ 
+  add_assoc_string(ctrl_array, "oid", ctrl->ldctl_oid,1); 
+  add_assoc_bool(ctrl_array, "iscritical", ctrl->ldctl_iscritical); 
+  add_assoc_stringl(ctrl_array, "value", ctrl->ldctl_value.bv_val, 
+   ctrl->ldctl_value.bv_len,1); 
+  add_next_index_zval (*serverctrls, ctrl_array); 
+  ctrlp++; 
+ } 
+ ldap_controls_free (lserverctrls); 
+ } 
    case 6 : 
    zval_dtor(*referrals); 
    if (array_init(*referrals) == FAILURE) {

वास्तव में एकमात्र विकल्प सक्रिय निर्देशिका विन्यास बदल सकते हैं और अधिक से अधिक परिणाम सीमा बढ़ाने का होगा छोड़ दिया है। प्रासंगिक विकल्प को MaxPageSize कहा जाता है और ntdsutil.exe का उपयोग करके बदला जा सकता है - कृपया "How to view and set LDAP policy in Active Directory by using Ntdsutil.exe" देखें।

संपादित (COM के संदर्भ में):

या आप इसके विपरीत जाने के लिए और के रूप में linkeykanal द्वारा प्रदान में सुझाव दिया ADODB के माध्यम से COM-दृष्टिकोण का उपयोग कर सकते हैं।

+0

शानदार उत्तर! बहुत बहुत धन्यवाद, इससे मुझे बहुत मदद मिली! – Christian

+2

अब इसकी स्थिति क्या है कि PHP 5.4 पेजेड एलडीएपी परिणामों का समर्थन करता है? – Squazic

+1

@ स्क्वैज़िक: नीचे दिए गए जवाब http://stackoverflow.com/a/10140166/11354 देखें। लगता है कि PHP 5.4 के साथ शुरू करने योग्य लगता है। –

3

यह एक पूर्ण उत्तर नहीं है, लेकिन this guy इसे करने में सक्षम था। मुझे समझ में नहीं आया कि उसने क्या किया, हालांकि।

वैसे, आंशिक उत्तर यह है कि आप परिणामों के "पृष्ठ" प्राप्त कर सकते हैं। documentation से:

resource ldap_search (resource $link_identifier , string $base_dn , 
    string $filter [, array $attributes [, int $attrsonly [, int $sizelimit [, 
    int $timelimit [, int $deref ]]]]]) 
... 

sizelimit लाई गई प्रविष्टियों की गिनती सीमित करने के लिए आप सक्षम बनाता है। इसे 0 पर सेट करने का मतलब कोई सीमा नहीं है।

नोट: यह पैरामीटर सर्वर-साइड प्रीसेट सिज़ेलिमिट को ओवरराइड नहीं कर सकता है। हालांकि आप इसे कम सेट कर सकते हैं। कुछ निर्देशिका सर्वर होस्ट प्रविष्टियों की प्रीसेट संख्या से अधिक नहीं लौटने के लिए कॉन्फ़िगर किया जाएगा। यदि यह होता है, तो सर्वर इंगित करेगा कि उसने केवल आंशिक परिणाम सेट लौटा दिया है। यह तब भी होता है जब आप प्राप्त प्रविष्टियों की गिनती को सीमित करने के लिए इस पैरामीटर का उपयोग करते हैं।

मुझे नहीं पता कि कैसे निर्दिष्ट करना है कि आप किसी निश्चित स्थिति से प्रारंभ करना चाहते हैं। हां, आपको अपना पहला 1000 प्राप्त करने के बाद, मुझे नहीं पता कि अब आपको कैसे निर्दिष्ट करना है। उम्मीद है कि कोई और आपकी मदद कर सकता है :)

6

पेज 5.4 के लिए समर्थन PHP 5.4 में जोड़ा गया था।

अधिक जानकारी के लिए ldap_control_paged_result देखें।

0

यहां एक विकल्प है (जो पूर्व PHP 5.4 काम करता है)। आप 10,000 रिकॉर्ड है, तो आप प्राप्त करने की आवश्यकता है, लेकिन आपका विज्ञापन सर्वर केवल 5,000 प्रति पृष्ठ देता है:

$ldapSearch = ldap_search($ldapResource, $basedn, $filter, array('member;range=0-4999')); 
$ldapResults = ldap_get_entries($dn, $ldapSearch); 
$members = $ldapResults[0]['member;range=0-4999']; 

$ldapSearch = ldap_search($ldapResource, $basedn, $filter, array('member;range=5000-10000')); 
$ldapResults = ldap_get_entries($dn, $ldapSearch); 
$members = array_merge($members, $ldapResults[0]['member;range=5000-*']); 
0

मैं का उपयोग कर ldap_control_paged_result

ldap_control_paged_result आकार सीमा के आस-प्राप्त करने में सक्षम था भेजकर LDAP पृष्ठांकन सक्षम करने के लिए प्रयोग किया जाता है अंकन नियंत्रण। नीचे दिए गए फ़ंक्शन ने मेरे मामले में पूरी तरह से काम किया।

function retrieves_users($conn) 
    { 
     $dn  = 'ou=,dc=,dc='; 
     $filter = "(&(objectClass=user)(objectCategory=person)(sn=*))"; 
     $justthese = array(); 

     // enable pagination with a page size of 100. 
     $pageSize = 100; 

     $cookie = ''; 

     do { 
      ldap_control_paged_result($conn, $pageSize, true, $cookie); 

      $result = ldap_search($conn, $dn, $filter, $justthese); 
      $entries = ldap_get_entries($conn, $result); 

      if(!empty($entries)){ 
       for ($i = 0; $i < $entries["count"]; $i++) { 
        $data['usersLdap'][] = array(
          'name' => $entries[$i]["cn"][0], 
          'username' => $entries[$i]["userprincipalname"][0] 
        ); 
       } 
      } 
      ldap_control_paged_result_response($conn, $result, $cookie); 

     } while($cookie !== null && $cookie != ''); 

     return $data; 
    } 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^