如何在 Laravel 中从 AD LDAP 获取所有用户而不会出现超时或内存问题?

问题描述 投票:0回答:1

我目前正在开发一个 Laravel 10 应用程序,该应用程序使用 AdLdap2 包和 PHP 的 LDAP 函数 (PHP 8) 与 Active Directory (AD) 集成。然而,当我尝试从 LDAP 服务器获取所有用户(超过 20,000 个)时,我遇到了挑战。

以下是我尝试过的两种方法: 方法一:使用AdLdap2包

private function handleAdLdapUsersEx($provider): void
{
    try {
        $pageSize = 200;

        if ($this->searchBase->filter) {
            $provider->where($this->searchBase->filter);
        }

        $pagedUsers = $provider->select('distinguishedname', 'givenname', 'name', 'objectguid', 'samaccountname', 'userprincipalname', 'mail')
            ->whereEnabled()
            ->limit($pageSize)
            ->paginate($pageSize, $this->currentPage);
        
        dump($pagedUsers->count());
        
        if ($pagedUsers->count() > 0) {
            collect($pagedUsers->getResults())->chunk(100)->each(function ($chunkedUsers) {
                $this->handleBulk($chunkedUsers);
                unset($chunkedUsers);
                gc_collect_cycles();
            });

            if ($pagedUsers->count() === $pageSize) {
                ImportUsersJob::dispatch($this->searchBase, $this->ldapConnector, $this->ldapConfig, $this->currentPage + 1);
            }
        }
    } catch (\Exception $e) {
        dd($e->getMessage());
    }
}

在这种方法中,我设置了分页限制,即使有限制和分页,我也能在一页中获取所有记录,但仍然遇到超时。设置 public $timeout = 600;有效,但我想避免硬编码超时。

方法2:使用PHP LDAP函数

private function handleAdLdapUsers($provider, $ldapConnector): void
{
    try {
        $usersFetched = 0;
        $lastUserEntry = null;

        $ldapConnection = ldap_connect($provider->getConnection()->getHost());
        ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
        ldap_bind($ldapConnection, $ldapConnector->getUsernames(), $ldapConnector->getPassword());

        $filter = !empty($this->searchBase->filter) ? $this->searchBase->filter : "(objectClass=*)";

        $result = @ldap_search($ldapConnection, $provider->getDn(), $filter, [], 0, 1);
        $firstEntry = ldap_first_entry($ldapConnection, $result);

        while ($firstEntry) {
            $attributes = ldap_get_attributes($ldapConnection, $firstEntry);

            $users = $provider->select('distinguishedname', 'givenname', 'name', 'objectguid', 'samaccountname', 'userprincipalname', 'mail', 'usncreated')
                ->whereEnabled()
                ->get($attributes);

            if ($users->count() > 0) {
                $this->handleBulk($users);
                $usersFetched = $users->count();
            } else {
                break;
            }

            $lastUserEntry = ldap_next_entry($ldapConnection, $firstEntry);
            $firstEntry = $lastUserEntry;
        }

        ldap_unbind($ldapConnection);
    } catch (\Exception $e) {
        dd($e->getMessage());
    }
}

此方法返回“超出大小限制”警告,并且仅获取 1000 条记录。我用 @ldap_search 抑制了警告,但我仍然需要一种方法来获取所有用户(可能超过 50,000 个),而不会达到大小限制或遇到内存问题。

  1. 如何修改查询或分页以有效地处理获取所有用户?
  2. 在 Laravel 中查询 LDAP 时是否有处理大型数据集的最佳实践?
  3. 有没有办法配置 LDAP 服务器以允许获取超过默认大小限制的内容?

任何帮助或指导将不胜感激!

php laravel ldap ldap-query adldap
1个回答
0
投票

不要抑制警告。使用

@
抑制它对于使代码获取更多结果没有任何帮助 – 它仍然获得不完整的数据,除了现在它安静地 获得不完整的数据 – 一旦代码被修复,警告将不会出现无论如何。

ldap_search()
采用
$controls
参数,您可以通过该参数请求分页搜索结果。请参阅LDAP 控件。由
ldap_parse_result()
解析的结果将有一个带有“cookie”的相应控件,需要将其传递给另一个 ldap_search() 以检索下一页。

$req_controls = [
    ["oid" => LDAP_CONTROL_PAGEDRESULTS, "value" => ["size" => 50"]],
];

如果您特别想要用户,请勿过滤

(objectClass=*)
;过滤
(objectCategory=user)
(这是 AD 特定的属性)以减少无用结果的数量。

ldap_search() 还采用

$attributes
参数。现在,您正在检索所有属性,然后仅选择您想要的几个属性,这就像当您想要的只是两列时执行
SELECT * FROM
。不要这样做,而是将所需属性的列表传递给 ldap_search() 以减少传输的数据量(即使不一定是条目量)。

© www.soinside.com 2019 - 2024. All rights reserved.