FusionDirectory
class_managementFilter.inc
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4 
5  Copyright (C) 2017-2019 FusionDirectory
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 
26 {
27  protected $types;
28 
29  protected $searchAttributes = [];
30  protected $scope = 'one';
31  protected $showTemplates = FALSE;
32 
33  protected $search = '';
34 
35  protected $filterElements = [];
36 
37  protected $fixedScope;
38 
39  /* The management class */
40  public $parent;
41 
42  public $pid;
43 
49  function __construct (management $parent, bool $fixedScope = NULL, array $filterElementDefinitions = [])
50  {
51  global $config;
52 
53  $this->parent = $parent;
54 
55  $this->pid = preg_replace('/[^0-9]/', '', microtime(TRUE));
56 
57  foreach ($this->parent->objectTypes as $type) {
58  $this->types['filter_type_'.$type] = [
59  'show' => TRUE,
60  'filters' => [],
61  'infos' => objects::infos($type),
62  ];
63  }
64 
65  $this->filterElements = [];
66  foreach ($filterElementDefinitions as $filterElementDefinition) {
67  list($class, $args) = $filterElementDefinition;
68  $this->filterElements[] = new $class($this, ...$args);
69  }
70 
71  $this->fixedScope = $fixedScope;
72  }
73 
74  function setScope (string $scope)
75  {
76  $this->scope = $scope;
77  }
78 
79  protected function showScope (): bool
80  {
81  if ($this->fixedScope !== NULL) {
82  return !$this->fixedScope;
83  }
84  return $this->parent->listing->getBaseMode();
85  }
86 
87  function addElement (FilterElement $element)
88  {
89  $this->filterElements[] = $element;
90  }
91 
92  function update (string $base)
93  {
94  global $ui;
95 
96  if (isset($_POST['FILTER_PID']) && ($_POST['FILTER_PID'] == $this->pid)) {
97  // Load post values and adapt filter, base and scope accordingly
98  foreach ($this->types as $key => &$data) {
99  $data['show'] = isset($_POST[$key]);
100  }
101  unset($data);
102 
103  $this->showTemplates = isset($_POST['filter_type_TEMPLATE']);
104 
105  if ($this->showScope()) {
106  $this->scope = (isset($_POST['SCOPE']) ? 'sub' : 'one');
107  }
108 
109  $this->search = (isset($_POST['SEARCH']) ? $_POST['SEARCH'] : '');
110 
111  foreach ($this->filterElements as $element) {
112  $element->update();
113  }
114  }
115 
116  foreach ($this->parent->objectTypes as $type) {
117  $attrs = objects::getSearchedAttributes($type);
118 
119  $this->searchAttributes[$type] = [];
120  $this->parent->listing->fillSearchedAttributes($type, $attrs);
121  foreach ($attrs as $attr => $acl) {
122  $rights = $ui->get_permissions($base, $acl, $attr);
123  if (strpos($rights, 'r') !== FALSE) {
124  $this->searchAttributes[$type][] = $attr;
125  }
126  }
127  }
128  }
129 
133  function render (): string
134  {
135  $smarty = get_smarty();
136 
137  $smarty->assign('SCOPE', $this->scope);
138  $smarty->assign('SHOWSCOPE', $this->showScope());
139  $smarty->assign('FILTER_PID', $this->pid);
140  $smarty->assign('SEARCH', $this->search);
141  $smarty->assign('TYPES', $this->types);
142 
143  $searchAttrs = [];
144  foreach ($this->searchAttributes as $type => $attrs) {
145  foreach ($attrs as $attr) {
146  $searchAttrs[] = strtolower($type).'/'.$attr;
147  }
148  }
149  $smarty->assign('SEARCHDESC', sprintf(_('Searches in %s'), implode(', ', $searchAttrs)));
150 
151  $parentClass = get_class($this->parent);
152  if (!$parentClass::$skipTemplates) {
153  $smarty->assign('TEMPLATES', $this->showTemplates);
154  }
155  $elements = [];
156  foreach ($this->filterElements as $element) {
157  $elements[] = $element->render();
158  }
159  $smarty->assign('FILTERS', $elements);
160 
161  // load the file from the theme folder
162  $file = get_template_path('management/filter.tpl');
163 
164  // Load template
165  return $smarty->fetch($file);
166  }
167 
168  function query (array $attrs, string $base): array
169  {
170  global $ui;
171 
172  $objectTypeCount = [];
173  $entries = [];
174  $row = 0;
175  $ui->getSizeLimitHandler()->setLimitExceeded(FALSE);
176  foreach ($this->parent->objectTypes as $type) {
177  $infos = $this->types['filter_type_'.$type]['infos'];
178  if ($this->scope == 'one') {
179  $searchBase = (empty($infos['ou']) ? $base : $infos['ou'].$base);
180  } else {
181  $searchBase = $base;
182  }
183 
184  $attrsAsked = $attrs;
185  if (!empty($infos['mainAttr']) && !isset($attrsAsked[$infos['mainAttr']])) {
186  /* Ask for mainAttr */
187  $attrsAsked[$infos['mainAttr']] = '*';
188  }
189  if (!empty($infos['nameAttr']) && !isset($attrsAsked[$infos['nameAttr']])) {
190  /* Ask for nameAttr */
191  $attrsAsked[$infos['nameAttr']] = '*';
192  }
193 
194  foreach ($attrsAsked as $attr => $data) {
195  // TODO: find a better way to avoid Exceptions
196  $category = $ui->getAttributeCategory($type, $attr);
197  if ($category === FALSE) {
198  unset($attrsAsked[$attr]);
199  }
200  }
201 
202  $elementFilters = [];
203  if (!empty($this->search)) {
204  if (preg_match('/^\(.+\)$/', $this->search)) {
205  $elementFilters[] = $this->search;
206  } else {
207  $searchAttributesTmp = $this->searchAttributes[$type];
208  if ($this->showTemplates) {
209  $searchAttributesTmp[] = '_template_cn';
210  }
211  $elementFilters[] = '(|('.implode('=*'.ldap_escape_f($this->search).'*)(', $searchAttributesTmp).'=*'.ldap_escape_f($this->search).'*))';
212  }
213  }
214 
215  $typeElementFilters = $elementFilters;
216  foreach ($this->filterElements as $element) {
217  $skip = $element->getFilters($type, $typeElementFilters);
218  if ($skip === TRUE) {
219  continue 2;
220  }
221  }
222  $filter = '';
223  if (!empty($typeElementFilters)) {
224  $filter = '(&'.implode('', $typeElementFilters).')';
225  }
226 
227  $parentClass = get_class($this->parent);
228  if (!$parentClass::$skipTemplates && $this->showTemplates) {
229  try {
230  $ldapEntries = objects::ls($type, $attrsAsked, (($this->scope == 'one') ? 'ou=templates,'.$searchBase : $searchBase), $filter, TRUE, $this->scope, TRUE);
231 
232  $objectTypeCount['template_'.$type] = count($ldapEntries);
233  foreach ($ldapEntries as $dn => $entry) {
234  $entries[$dn] = new ListingEntry($this->parent->listing, 'template_'.$type, $dn, $entry, $row++);
235  }
236  } catch (FusionDirectoryException $e) {
237  $warning = new FusionDirectoryWarning(
238  nl2br(htmlescape(sprintf(
239  _("Could not search for \"%s\" templates:\n%s"),
240  $this->types['filter_type_'.$type]['infos']['name'],
241  $e->getMessage()
242  ))),
243  0,
244  $e
245  );
246  $warning->display();
247  }
248  }
249 
250  if (!$this->types['filter_type_'.$type]['show']) {
251  continue;
252  }
253 
254  try {
255  $ldapEntries = objects::ls($type, $attrsAsked, $searchBase, $filter, TRUE, $this->scope, FALSE, TRUE);
256 
257  $ldapEntries = $this->filterEntries($ldapEntries);
258  } catch (FusionDirectoryException $e) {
259  $warning = new FusionDirectoryWarning(
260  nl2br(htmlescape(sprintf(
261  _("Could not search for \"%s\":\n%s"),
262  $this->types['filter_type_'.$type]['infos']['name'],
263  $e->getMessage()
264  ))),
265  0,
266  $e
267  );
268  $warning->display();
269  $this->types['filter_type_'.$type]['show'] = FALSE;
270  continue;
271  }
272 
273  $objectTypeCount[$type] = count($ldapEntries);
274  foreach ($ldapEntries as $dn => $entry) {
275  if (isset($entries[$dn])) {
276  trigger_error('Same dn '.$dn.' found as several object types');
277  }
278  $entries[$dn] = new ListingEntry($this->parent->listing, $type, $dn, $entry, $row++);
279  }
280  }
281 
282  return [$entries, $objectTypeCount];
283  }
284 
285  protected function filterEntries (array $ldapEntries): array
286  {
287  if (!empty($this->parent->whiteList)) {
288  foreach ($ldapEntries as $dn => $entry) {
289  if (in_array($dn, $this->parent->whiteList['dn'])) {
290  continue;
291  }
292  foreach ($this->parent->whiteList['branches'] as $branch) {
293  if (preg_match('/'.preg_quote($branch, '/').'$/', $dn)) {
294  continue 2;
295  }
296  }
297  unset($ldapEntries[$dn]);
298  }
299  }
300  if (isset($this->parent->blackList)) {
301  foreach ($this->parent->blackList as $attr_name => $attr_values) {
302  foreach ($attr_values as $match) {
303  foreach ($ldapEntries as $dn => $entry) {
304  if (isset($entry[$attr_name])) {
305  $test = $entry[$attr_name];
306  if (!is_array($test)) {
307  $test = [$test];
308  }
309  if (in_array($match, $test)) {
310  unset($ldapEntries[$dn]);
311  }
312  }
313  }
314  }
315  }
316  }
317 
318  return $ldapEntries;
319  }
320 }
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
get_template_path($filename='', $plugin=FALSE, $path='')
Return themed path for specified base file.
Definition: functions.inc:174
This class handles an element from the management filter box.
static ls($types, $attrs=NULL, string $ou=NULL, string $filter='', bool $checkAcl=FALSE, string $scope='subtree', bool $templateSearch=FALSE, bool $sizeLimit=FALSE)
Get list of object of objectTypes from $types in $ou.
& get_smarty()
Get global smarty object.
Definition: functions.inc:324
This class handles the management filter box.
Parent class for all exceptions thrown in FusionDirectory.
__construct(management $parent, bool $fixedScope=NULL, array $filterElementDefinitions=[])
Create a management filter.
Management base class.