source: sandbox/workflow/trunk/inc/class.WorkflowLDAP.inc.php @ 2372

Revision 2372, 21.5 KB checked in by pedroerp, 14 years ago (diff)

Ticket #609 - Merged 2197:2356 /sandbox/workflow/branches/609/ em /sandbox/workflow/trunk.

Line 
1<?php
2/**************************************************************************\
3* eGroupWare                                                               *
4* http://www.egroupware.org                                                *
5* --------------------------------------------                             *
6*  This program is free software; you can redistribute it and/or modify it *
7*  under the terms of the GNU General Public License as published by the   *
8*  Free Software Foundation; either version 2 of the License, or (at your  *
9*  option) any later version.                                              *
10\**************************************************************************/
11
12/**
13 * Implements common LDAP methods
14 * @author Sidnei Augusto Drovetto Jr. - drovetto@gmail.com
15 * @version 1.0
16 * @package Workflow
17 * @license http://www.gnu.org/copyleft/gpl.html GPL
18 */
19class WorkflowLDAP
20{
21        /**
22         * @var resource $dataSource Recurso de conexão com o LDAP
23         * @access private
24         */
25        private $dataSource;
26
27        /**
28         * @var string $userContext Contexto do usuário
29         * @access private
30         */
31        private $userContext;
32
33        /**
34         * @var string $groupContext Contexto do grupo
35         * @access private
36         */
37        private $groupContext;
38
39        /**
40         * @var string $ldapContext Contexto do LDAP
41         * @access private
42         */
43        private $ldapContext;
44
45        /**
46         * Construtor da classe
47         * @return object
48         * @access public
49         */
50        function WorkflowLDAP()
51        {
52                $this->dataSource =& Factory::getInstance('WorkflowObjects')->getLDAP();
53
54                /* get the required parameters */
55                $info = (isset($GLOBALS['phpgw_info']['server']['ldap_context'])) ?
56                        $GLOBALS['phpgw_info']['server'] :
57                        $_SESSION['phpgw_info']['workflow']['server'];
58                $ldapConfigValues = galaxia_get_config_values(array('ldap_user_context' => '', 'ldap_group_context' => ''));
59                if (empty($ldapConfigValues['ldap_user_context']))
60                        $ldapConfigValues['ldap_user_context'] = $info['ldap_context'];
61                if (empty($ldapConfigValues['ldap_group_context']))
62                        $ldapConfigValues['ldap_group_context'] = $info['ldap_group_context'];
63                $this->userContext = $ldapConfigValues['ldap_user_context'];
64                $this->groupContext = $ldapConfigValues['ldap_group_context'];
65                $this->ldapContext = $ldapConfigValues['ldap_user_context'];
66
67                $this->cache = array(
68                        'getEntities' => array(),
69                        'getUserGroups' => array(),
70                        'getGroupUsers' => array(),
71                        'getOrganizations' => array(),
72                        'getNames' => array()
73                );
74        }
75
76        /**
77         * Checa se um método, e seus parâmetros, já estãoe em cache
78         * @param string $methodName O nome do método que se quer verificar
79         * @param string $parameters Parâmetros passados para o método (serializados)
80         * @return bool true se foi encontrada uma versão em cache dos dados solicitados e false caso contrário
81         * @access private
82         */
83        private function checkCache($methodName, $parameters)
84        {
85                return isset($this->cache[$methodName][$parameters]);
86        }
87
88        /**
89         * Pega a informação, em cache, de um método e seus parâmetros
90         * @param string $methodName O nome do método que está em cache
91         * @param string $parameters Parâmetros passados para o método (serializados)
92         * @return mixed O retorno do método usando os parâmetros passados
93         * @access private
94         */
95        private function getCache($methodName, $parameters)
96        {
97                return $this->cache[$methodName][$parameters];
98        }
99
100        /**
101         * Coloca em cache um método e seus parâmetros
102         * @param string $methodName O nome do método
103         * @param string $parameters Parâmetros passados para o método (serializados)
104         * @param mixed $output Saída do método usando os parâmetros passados
105         * @return mixed A saída igual ao parâmetro $output
106         * @access private
107         */
108        private function setCache($methodName, $parameters, $output)
109        {
110                $this->cache[$methodName][$parameters] = $output;
111                return $output;
112        }
113
114        /**
115         * Faz consultas ao LDAP
116         * @param string $context Contexto das entidades
117         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
118         * @param array $elements Array dos campos que se deseja obter
119         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
120         * @param string $elementSort O elemento pelo qual se quer ordenar o resultado
121         * @return mixed Array do resultado. Ou false em caso de erro
122         * @access private
123         */
124        private function runLDAP($context, $filter, $elements, $depthSearch = false, $elementSort = null)
125        {
126                if ($depthSearch)
127                        $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, $elements);
128                else
129                        $resourceIdentifier = ldap_list($this->dataSource, $context, $filter, $elements);
130
131                if (!$resourceIdentifier)
132                        return false;
133
134                if (!is_null($elementSort))
135                        ldap_sort($this->dataSource, $resourceIdentifier, $elementSort);
136
137                $output = ldap_get_entries($this->dataSource, $resourceIdentifier);
138                return $output;
139        }
140
141        /**
142         * Faz consultas ao LDAP (inclusive com campos binários)
143         * @param string $context Contexto das entidades
144         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
145         * @param array $elements Array dos campos que se deseja obter
146         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
147         * @param string $elementSort O elemento pelo qual se quer ordenar o resultado
148         * @return mixed Array do resultado. Ou false em caso de erro
149         * @access private
150         */
151        private function runBinaryLDAP($context, $filter, $elements, $depthSearch = false, $elementSort = null)
152        {
153                if ($depthSearch)
154                        $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, $elements);
155                else
156                        $resourceIdentifier = ldap_list($this->dataSource, $context, $filter, $elements);
157
158                if (!$resourceIdentifier)
159                        return false;
160
161                if (!is_null($elementSort))
162                        ldap_sort($this->dataSource, $resourceIdentifier, $elementSort);
163
164                $entry = ldap_first_entry($this->dataSource, $resourceIdentifier);
165                if (!$entry)
166                        return array();
167
168                $output = array();
169                $counter = 0;
170                do
171                {
172                        $attributes = ldap_get_attributes($this->dataSource, $entry);
173                        for ($i = 0; $i < $attributes['count']; $i++)
174                                $output[$counter][$attributes[$i]] = ldap_get_values_len($this->dataSource, $entry, $attributes[$i]);
175
176                        $counter++;
177                } while ($entry = ldap_next_entry($this->dataSource, $entry));
178
179                return $output;
180        }
181
182        /**
183         * Busca entidades (usuários, grupos ou listas públicas) do LDAP
184         * @param string $context Contexto das entidades
185         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
186         * @param array $elements Array dos campos que representa, nesta ordem: o ID, o nome e o e-mail da entidade
187         * @param char $type O tipo da entidade: 'u' para usuários; 'g' para grupos; e 'l' para listas públicas
188         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
189         * @return array Array das entidades
190         * @access private
191         */
192        private function getEntities($context, $filter, $elements, $type, $depthSearch = false)
193        {
194                /* check if the required information is in cache */
195                $methodName = 'getEntities';
196                $parameters = serialize(func_get_args());
197                if ($this->checkCache($methodName, $parameters))
198                        return $this->getCache($methodName, $parameters);
199
200                $result = $this->runLDAP($context, $filter, $elements, $depthSearch, $elements[1]);
201
202                $output = array();
203                for ($i = 0; $i < $result['count']; $i++)
204                {
205                        $output[] = array(
206                                'id' => $result[$i][$elements[0]][0],
207                                'name' => $result[$i][$elements[1]][0],
208                                'type' => $type,
209                                'mail' => $result[$i][$elements[2]][0]);
210                }
211
212                /* store the information in cache and return the output */
213                return $this->setCache($methodName, $parameters, $output);
214        }
215
216        /**
217         * Retorna os grupos de um usuário
218         * @param int $userID O ID do usuário
219         * @return array Array dos grupos
220         * @access public
221         */
222        function getUserGroups($userID)
223        {
224                /* do not perform any search if the user is '*' */
225                if ($userID == '*')
226                        return array();
227
228                /* check if the required information is in cache */
229                $methodName = 'getUserGroups';
230                $parameters = serialize(func_get_args());
231                if ($this->checkCache($methodName, $parameters))
232                        return $this->getCache($methodName, $parameters);
233
234                /* check for error in connection */
235                if (!$this->dataSource)
236                        return false;
237
238                /* first, get the UID */
239                $resourceIdentifier = ldap_search($this->dataSource, $this->userContext, "(&(phpgwaccounttype=u)(uidnumber={$userID}))", array('uid'));
240                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
241                if (!isset($result[0]['uid'][0]))
242                        return false;
243                $userLogin = $result[0]['uid'][0];
244
245                /* initialize some variables */
246                $output = array();
247
248                /* search the LDAP tree */
249                $resourceIdentifier = ldap_search($this->dataSource, $this->groupContext, "(&(phpgwaccounttype=g)(memberuid={$userLogin}))", array('gidnumber'));
250                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
251                for ($i = 0; $i < $result['count']; $i++)
252                        $output[] = $result[$i]['gidnumber'][0];
253
254                /* store the information in cache and return the output */
255                return $this->setCache($methodName, $parameters, $output);
256        }
257
258        /**
259         * Retorna os usuários de um grupo
260         * @param int $groupID O ID do grupo
261         * @return array Array dos usuários
262         * @access public
263         */
264        function getGroupUsers($groupID)
265        {
266                /* check if the required information is in cache */
267                $methodName = 'getGroupUsers';
268                $parameters = serialize(func_get_args());
269                if ($this->checkCache($methodName, $parameters))
270                        return $this->getCache($methodName, $parameters);
271
272                /* check for error in connection */
273                if (!$this->dataSource)
274                        return false;
275
276                /* first, we get the UIDs that are members of the group */
277                $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(&(phpgwaccounttype=g)(gidnumber={$groupID}))", array('memberuid'));
278                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
279                if (!isset($result[0]['memberuid'][0]))
280                        return false;
281
282                $userLogins = $result[0]['memberuid'];
283                unset($userLogins['count']);
284
285                /* load the user information ten users at a time. This approach was proven to be faster on some systems */
286                $result = array();
287                while (count($userLogins) > 0)
288                {
289                        $selectedUserLogins = array_splice($userLogins, 0, 10);
290                        $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(&(phpgwaccounttype=u)(|" . implode('', array_map(create_function('$a', 'return "(uid={$a})";'), $selectedUserLogins)) . "))", array('cn', 'uidnumber'));
291                        $result = array_merge($result, ldap_get_entries($this->dataSource, $resourceIdentifier));
292                        unset($result['count']);
293                }
294
295                $output = array();
296                $userCount = count($result);
297                for ($i = 0; $i < $userCount; $i++)
298                        $output[] = array(
299                                'account_id' => $result[$i]['uidnumber'][0],
300                                'account_name' => $result[$i]['cn'][0]);
301
302                /* sort the result */
303                usort($output, create_function('$a,$b', 'return strcasecmp($a[\'account_name\'],$b[\'account_name\']);'));
304
305                /* store the information in cache and return the output */
306                return $this->setCache($methodName, $parameters, $output);
307        }
308
309        /**
310         * Retorna as organizações do nível raiz
311         * @return array Array de organizações
312         * @access public
313         */
314        function getOrganizations()
315        {
316                /* check if the required information is in cache */
317                $methodName = 'getOrganizations';
318                $parameters = serialize(func_get_args());
319                if ($this->checkCache($methodName, $parameters))
320                        return $this->getCache($methodName, $parameters);
321
322                /* check for error in connection */
323                if (!$this->dataSource)
324                        return false;
325
326                /* load the sectors of level 0 as organizations, then format the data */
327                $output = array_map(create_function('$a', 'return $a[\'ou\'];'), $this->getSectors());
328
329                /* store the information in cache and return the output */
330                return $this->setCache($methodName, $parameters, $output);
331        }
332
333        /**
334         * Retorna os setores de um determinado contexto
335         * @param string $organization A organização a partir da qual a busca deve inciar. Utilize null para o nível raiz
336         * @param bool $recursive Indica se a busca deve ser recursiva ou não. true indica que deve ser recursiva e false que não deve ser recursiva
337         * @param string $contextBase A base do contexto. Utilize null para o contexto padrão
338         * @param int $level Indica o nível atual de recursão
339         * @return array Array de setores
340         * @access public
341         */
342        function getSectors($organization = null, $recursive = false, $contextBase = null, $level = 0)
343        {
344                /* determines the context in which the search will be performed */
345                $context = (!is_null($contextBase) ? $contextBase : $this->ldapContext);
346                $context = (!is_null($organization) ? 'ou=' . $organization . ',' : '') . $context;
347
348                /* search for the sectors */
349                $resourceIdentifier = @ldap_list($this->dataSource, $context, '(objectClass=organizationalUnit)', array('ou'));
350                if ($resourceIdentifier === false)
351                        return false;
352
353                ldap_sort($this->dataSource, $resourceIdentifier, 'ou');
354                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
355
356                /* collect the data */
357                $output = array();
358                for ($i = 0; $i < $result['count']; $i++)
359                {
360                        $output[] = array(
361                                'dn' => $result[$i]['dn'],
362                                'ou' => $result[$i]['ou'][0],
363                                'level' => $level);
364
365                        /* if requested, perform a recursive search */
366                        if ($recursive)
367                                $output = array_merge($output, $this->getSectors($result[$i]['ou'][0], $recursive, $context, $level + 1));
368                }
369
370                return $output;
371        }
372
373        /**
374         * Retorna os usuários de um determinado contexto
375         * @param string $context O contexto a partir do qual a busca deve começar
376         * @return array Array dos usuários encontrados
377         * @access public
378         */
379        function getUsers($context)
380        {
381                $filter = '(&(phpgwaccounttype=u)(!(phpgwAccountVisible=-1)))';
382                $elements = array('uidnumber', 'cn', 'mail');
383                return $this->getEntities($context, $filter, $elements, 'u', false);
384        }
385
386        /**
387         * Retorna os grupos de um determinado contexto
388         * @param string $context O contexto a partir do qual a busca deve começar
389         * @return array Array dos grupos encontrados
390         * @access public
391         */
392        function getGroups($context)
393        {
394                $filter = '(phpgwaccounttype=g)';
395                $elements = array('gidnumber', 'cn', 'mail');
396                return $this->getEntities($context, $filter, $elements, 'g', false);
397        }
398
399        /**
400         * Retorna listas públicas de um determinado contexto
401         * @param string $context O contexto a partir do qual a busca deve começar
402         * @return array Array das listas públicas encontradas
403         * @access public
404         */
405        function getPublicLists($context)
406        {
407                $filter = '(phpgwaccounttype=l)';
408                $elements = array('uidnumber', 'cn', 'mail');
409                return $this->getEntities($context, $filter, $elements, 'l', false);
410        }
411
412        /**
413         * Retornar informação sobre um usuário
414         * @param int $userID O ID do usuário
415         * @return mixed Array contento informação sobre um usuário ou false se o usuário não for encontrado
416         * @access public
417         */
418        function getUserInfo($userID)
419        {
420                $filter = '(&(phpgwaccounttype=u)(uidnumber=' . $userID . '))';
421                $elements = array('uidnumber', 'cn', 'mail');
422                $output = $this->getEntities($this->ldapContext, $filter, $elements, 'u', true);
423                if (count($output) == 1)
424                        return $output[0];
425                else
426                        return false;
427        }
428
429        function getUserPicture($userID)
430        {
431                $userID = (int) $userID;
432                $filter = '(&(phpgwaccounttype=u)(uidnumber=' . $userID . '))';
433                $elements = array('jpegPhoto');
434                $result = $this->runBinaryLDAP($this->ldapContext, $filter, $elements, true);
435
436                if (isset($result[0]['jpegPhoto'][0]))
437                        return $result[0]['jpegPhoto'][0];
438
439                return false;
440        }
441
442        /**
443         * Retrieves information about a group
444         * @param int $userID The ID of the group
445         * @return mixed Array containing information about a group or false if the group is not found
446         * @access public
447         */
448        function getGroupInfo($groupID)
449        {
450                $filter = '(&(phpgwaccounttype=g)(gidnumber=' . $groupID . '))';
451                $elements = array('gidnumber', 'cn', 'mail');
452                $output = $this->getEntities($this->ldapContext, $filter, $elements, 'g', true);
453                if (count($output) == 1)
454                        return $output[0];
455                else
456                        return false;
457        }
458
459        /**
460         * Retorna o tipo de uma entidade
461         * @param int $entityID O ID da entidade
462         * @return string O tipo da entidade ('g' para grupo e 'u' para usuário)
463         * @access public
464         */
465        function getEntityType($entityID)
466        {
467                if ($entityID == '*')
468                        return false;
469
470                $output = $this->getUserInfo($entityID);
471                if (is_array($output))
472                        return 'u';
473                else
474                {
475                        $output = $this->getGroupInfo($entityID);
476                        if (is_array($output))
477                                return 'g';
478                }
479
480                return false;
481        }
482
483        /**
484         * Retorna o nome de uma entidade
485         * @param int $entityID O ID da entidade
486         * @return string O nome da entidade
487         * @access public
488         */
489        function getName($entityID)
490        {
491                if ($entityID == '*')
492                        return '*';
493                $output = $this->getUserInfo($entityID);
494                if (is_array($output))
495                        return $output['name'];
496                else
497                {
498                        $output = $this->getGroupInfo($entityID);
499                        if (is_array($output))
500                                return $output['name'];
501                }
502        }
503
504        /**
505         * Retorna os nomes de uma entidade
506         * @param array $entitiesID Os IDs das entidades
507         * @return string Os nomes das entidades
508         * @access public
509         */
510        function getNames($entitiesID)
511        {
512                /* check if the required information is in cache */
513                $methodName = 'getNames';
514                $parameters = serialize(func_get_args());
515                if ($this->checkCache($methodName, $parameters))
516                        return $this->getCache($methodName, $parameters);
517
518                /* check for error in connection */
519                if (!$this->dataSource)
520                        return false;
521
522                /* check for '*' */
523                $asteriskIndex = array_search('*', $entitiesID);
524                if ($asteriskIndex !== false)
525                        unset($entitiesID[$asteriskIndex]);
526
527                /* load the entity information ten entities at a time. This approach was proven to be faster on some systems */
528                $result = array();
529                while (count($entitiesID) > 0)
530                {
531                        $selectedEntitiesID = array_splice($entitiesID, 0, 10);
532                        $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(|" . implode('', array_map(create_function('$a', 'return "(|(&(uidnumber={$a})(|(phpgwaccounttype=u)(phpgwaccounttype=l)))(&(gidnumber={$a})(phpgwaccounttype=g)))";'), array_unique($selectedEntitiesID))) . ')', array('cn', 'uidnumber', 'gidnumber', 'phpgwaccounttype'));
533                        $result = array_merge($result, ldap_get_entries($this->dataSource, $resourceIdentifier));
534                        unset($result['count']);
535                }
536
537                $output = array();
538                $entityCount = count($result);
539                for ($i = 0; $i < $entityCount; $i++)
540                        $output[] = array(
541                                'id' => ($result[$i]['phpgwaccounttype'][0] == 'g') ? $result[$i]['gidnumber'][0] : $result[$i]['uidnumber'][0],
542                                'name' => $result[$i]['cn'][0]);
543
544                if ($asteriskIndex !== false)
545                        $output[] = array('id' => '*', 'name' => '*');
546
547                /* sort the result */
548                usort($output, create_function('$a,$b', 'return strcasecmp($a[\'name\'],$b[\'name\']);'));
549
550                /* store the information in cache and return the output */
551                return $this->setCache($methodName, $parameters, $output);
552        }
553
554        /**
555         * Faz uma busca (em todo o catálogo) por um nome
556         * @param string $searchTerm O termo que está sendo procurado (pode conter '*')
557         * @param bool $includeUsers Indica se na busca devem ser incluídos os registros referentes a usuários (true por padrão)
558         * @param bool $includeGroups Indica se na busca devem ser incluídos os registros referentes a grupos (false por padrão)
559         * @param bool $includeLists Indica se na busca devem ser incluídos os registros referentes a listas (false por padrão)
560         * @return array Uma array contendo os registros encontrados
561         * @access public
562         */
563        function search($searchTerm, $includeUsers = true, $includeGroups = false, $includeLists = false, $context = null)
564        {
565                if (!($includeUsers || $includeGroups || $includeLists))
566                        return false;
567
568                if (is_null($context))
569                        $context = $this->ldapContext;
570
571                /* check for error in connection */
572                if (!$this->dataSource)
573                        return false;
574
575                $entityFilter = array();
576                if ($includeUsers)
577                        $entityFilter[] = '(phpgwaccounttype=u)';
578                if ($includeGroups)
579                        $entityFilter[] = '(phpgwaccounttype=g)';
580                if ($includeLists)
581                        $entityFilter[] = '(phpgwaccounttype=l)';
582
583                if (count($entityFilter) > 1)
584                        $entityFilter = '(|' . implode('', $entityFilter) . ')';
585                else
586                        $entityFilter = $entityFilter[0];
587
588                $filter = "(&{$entityFilter}(cn={$searchTerm})(!(phpgwAccountVisible=-1)))";
589                $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, array('cn', 'uidnumber', 'gidnumber', 'phpgwaccounttype', 'mail'));
590                ldap_sort($this->dataSource, $resourceIdentifier, 'cn');
591                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
592
593                $output = array();
594                for ($i = 0; $i < $result['count']; $i++)
595                        $output[] = array(
596                                'id' => ($result[$i]['phpgwaccounttype'][0] == 'g') ? $result[$i]['gidnumber'][0] : $result[$i]['uidnumber'][0],
597                                'name' => $result[$i]['cn'][0],
598                                'mail' => $result[$i]['mail'][0],
599                                'type' => $result[$i]['phpgwaccounttype'][0],
600                                'dn' => $result[$i]['dn']
601                        );
602
603                /* store the information in cache and return the output */
604                return $output;
605        }
606
607        /**
608         * Retorna o contexto de usuários do LDAP
609         * @return string O contexto de usuários do LDAP
610         * @access public
611         */
612        function getUserContext()
613        {
614                return $this->userContext;
615        }
616
617        /**
618         * Retorna o contexto de grupos do LDAP
619         * @return string O contexto de grupos do LDAP
620         * @access public
621         */
622        function getGroupContext()
623        {
624                return $this->groupContext;
625        }
626
627        /**
628         * Retorna o contexto do LDAP
629         * @return string O contexto do LDAP
630         * @access public
631         */
632        function getLDAPContext()
633        {
634                return $this->ldapContext;
635        }
636
637        /**
638         * Retorna a organização de um DN
639         * @param mixed $DN O DN do usuário
640         * @return mixed Uma string contendo a organização ou false caso não seja achada a organização
641         * @access public
642         */
643        public function getOrganizationFromDN($DN)
644        {
645                $userContext = str_replace(' ', '', $this->userContext);
646                $DN = str_replace(' ', '', $DN);
647                $userInfo = array_reverse(explode(',', substr($DN, 0, - (strlen($userContext) + 1))));
648                foreach ($userInfo as $attributePair)
649                {
650                        list($name, $value) = explode('=', $attributePair, 2);
651                        if ($name === 'ou')
652                                return $value;
653                }
654
655                return false;
656        }
657}
658?>
Note: See TracBrowser for help on using the repository browser.