PHP ile LDAP tüm kullanıcıların numaralandırılması

3 Cevap php

Ben bir günlük cron olarak çalışan bir php komut dosyası oluşturmak istiyorum. Ne yapmak istiyorum, bir Active Directory içinde tüm kullanıcılar numaralandırmak her giriş, belirli alanları ayıklamak ve bir MySQL veritabanı içinde alanları güncelleştirmek için bu bilgileri kullanmaktır.

Temelde ne yapmak istiyorum, Active Directory ve MySQL tablo arasında belirli kullanıcı bilgilerini senkronize edilir.

Ben sorun Active Directory sunucusu üzerinde SizeLimit sık sık arama sonucunda 1000 girişlerinde ayarlanmış olmasıdır. Ben php function "ldap_next_entry" bir seferde sadece tek bir girişi getiriliyor toparlamaya olacağını umduğu, ancak "ldap_next_entry" diyebilirsin önce, ilk SizeLimit hatayı aştı tetikleyebilir "ldap_search", aramak zorunda.

Sunucudan SizeLimit çıkarılması dışında herhangi bir yolu var mı? Ben bir şekilde sonuçları "sayfalar" alabilir miyim?

BTW - Şu anda herhangi bir 3. parti kütüphaneler veya kod kullanarak değilim. Sadece ldap yöntemleri Phps. Her ne kadar, ben kesinlikle yardımcı olacak eğer bir kütüphaneyi kullanarak açık.

3 Cevap

Ben Zend Framework için Zend_Ldap geliştirirken aynı sorundan vurdu oldum. Ben asıl sorunun ne olduğunu anlatmaya çalışacağım, ama kısa yapmak için: nedeniyle tam olarak bu uzantı sınırlamalar it's currently not possible to use paged results from an Active Directory with an unpatched PHP (ext/ldap) sürümü.

Kullanıcının şeyi çözmeye çalışalım ... Microsoft Active Directory sunucu tarafı sonucu sayfalama gerçekleştirmek için bir sözde sunucu denetimi kullanır. Bu kontrol ist RFC 2696 "LDAP Control Extension for Simple Paged Results Manipulation" tarif edilmiştir.

ext/php ile ldap_set_option() and the LDAP_OPT_SERVER_CONTROLS ve LDAP_OPT_CLIENT_CONTROLS seçeneği sırasıyla aracılığıyla LDAP kontrolü uzantıları için bir erişim sunuyor. Sayfalı kontrolünü ayarlamak için denetimi-oid, (bu RFC açıklanan) 1.2.840.113556.1.4.319, ve biz kontrol değerini kodlamak için bilmek gerekir gerekiyor. Değeri (RFC kopyalanan) aşağıdaki SEQUENCE BER kodlu sürümünü sararak bir sekizli dize:

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

Bu yüzden önce LDAP sorgusunu yürütme uygun sunucu kontrolü ayarlayabilirsiniz:

$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
);

Bu bize LDAP / AD sunucusuna bir sayfalık sorgu göndermek için izin verir. Ama takip etmek daha fazla sayfa varsa nasıl anlarım ve nasıl biz bizim bir sonraki sorgu göndermek zorunda olan kontrol değeri ile belirtebilirim?

Biz saplanıyor giriyoruz ... sunucu belleği gerekli bilgileri içeren bir sonuç kümesi ile yanıt ancak PHP sonuç kümesinden tam olarak bu bilgileri almak için bir yöntem yoktur. PHP LDAP API işlevi ldap_parse_result() but the required last parameter serverctrlsp PHP işlevine maruz kalmayan bir sarıcı sağlar, böylece gerekli bilgileri almak için hiçbir yolu yoktur. A bug report bu sorun için dava açılmıştır, ancak 2005 yılından bu yana herhangi bir yanıt olmuştur. ldap_parse_result() function disk belleği sonuçları gibi çalışacak kullanarak, istenen parametreyi sağlanmışsa

$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);
    }
}

Eğer tek bir kod satırı var gördüğünüz gibi (*) Bu her şey işe yaramaz hale getirir. Benim yolda bu konuda bilgi seyrek olsa ben bir Iñaki Arenaza tarafından PHP 4.3.10 ext/ldap karşı yama bulundu ama ne ben bunu denemek ne yama bir PHP5'ta {uygulanabilir olmadığını ben biliyorum yaptım [(1)]}. Yama ldap_parse_result() PHP 7. parametre açığa kadar uzanır:

--- 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) {

Aslında sol tek seçenek Active Directory yapılandırmasını değiştirmek ve maksimum sonuç sınırını yükseltmek olacaktır. İlgili seçeneği MaxPageSize denir ve ntdsutil.exe ile değiştirilebilir - "How to view and set LDAP policy in Active Directory by using Ntdsutil.exe" bakın.

EDIT (COM referans):

Ya da yuvarlak başka bir yol gitmek ve link eykanal tarafından sağlanan önerildiği gibi ADODB üzerinden COM-yaklaşımı kullanabilirsiniz.

Disk belleği sonuçları için destek PHP 5.4 eklendi.

ldap_control_paged_result daha fazla bilgi için bkz.

Bu tam bir cevap değil, ama this guy bunu başardı. Ama, ne yaptığını anlamıyorum.

Bu arada, kısmi bir cevap size sonuç "sayfalar" olsun CAN olmasıdır. Kimden documentation:

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

sizelimit Eğer getirilen girişlerin sayısını sınırlamak için olanak sağlar. 0 ayarlanması sınırı yok demektir.

Note: This parameter can NOT override server-side preset sizelimit. You can set it lower though. Some directory server hosts will be configured to return no more than a preset number of entries. If this occurs, the server will indicate that it has only returned a partial results set. This also occurs if you use this parameter to limit the count of fetched entries.

Ben olsa, belli bir konumdan başlayarak aramak istediğiniz belirtmek için nasıl bilmiyorum. Yani, ilk 1000 aldıktan sonra, ben şimdi bir sonraki 1000 gerektiğini belirtmek için nasıl bilmiyorum. Umarım başkası size yardımcı olabilirim :)