dd3c9b335a14e40e00d74a8779dedfddcdabaf5f
1 <?php
3 class filter {
5 var $xmlData;
6 var $elements= array();
7 var $elementValues= array();
8 var $alphabetElements= array();
9 var $autocompleter= array();
10 var $category= "";
11 var $objectStorage= array();
12 var $objectBase= "";
13 var $base= "";
14 var $bases= array();
15 var $scope= "";
16 var $query;
17 var $initial= false;
18 var $baseMode= false;
19 var $scopeMode= "auto";
20 var $alphabet= null;
23 function filter($filename)
24 {
25 if (!$this->load($filename)) {
26 die("Cannot parse $filename!");
27 }
28 }
31 function load($filename)
32 {
33 $contents = file_get_contents($filename);
34 $this->xmlData= xml::xml2array($contents, 1);
36 if (!isset($this->xmlData['filter'])) {
37 return false;
38 }
40 $this->xmlData= $this->xmlData["filter"];
42 // Load filter
43 if (isset($this->xmlData['search'])) {
44 if (!isset($this->xmlData['search']['query'][0])){
45 $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
46 }
48 // Move information
49 $entry= $this->xmlData['search'];
50 $this->baseMode= $entry['base'];
51 $this->scopeMode= $entry['scope'];
52 $this->query= $entry['query'];
53 } else {
54 return false;
55 }
57 // Transfer initial value
58 if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
59 $this->initial= true;
60 }
62 // Generate formular data
63 if (isset($this->xmlData['element'])) {
64 if (!isset($this->xmlData['element'][0])){
65 $this->xmlData['element']= array($this->xmlData['element']);
66 }
67 foreach ($this->xmlData['element'] as $element) {
69 // Ignore elements without type
70 if (!isset($element['type']) || !isset($element['tag'])) {
71 next;
72 }
74 $tag= $element['tag'];
76 // Fix arrays
77 if (isset($element['value']) && !isset($element['value'][0])) {
78 $element['value']= array($element['value']);
79 }
81 // Store element for quick access
82 $this->elements[$tag] = $element;
84 // Preset elementValues with default values if exist
85 if (isset($element['default']) && !is_array($element['default'])) {
86 $this->elementValues[$tag] = $element['default'];
87 } else {
88 $this->elementValues[$tag] = "";
89 }
91 // Does this element react on alphabet links?
92 if (isset($element['alphabet']) && $element['alphabet'] == "true") {
93 $this->alphabetElements[]= $tag;
94 }
95 }
96 }
98 return true;
99 }
102 function getTextfield($element)
103 {
104 $tag= $element['tag'];
105 $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='30' maxlength='30' value='".$this->elementValues[$tag]."'>";
106 if (isset($element['autocomplete'])) {
107 $frequency= "0.5";
108 $characters= "1";
109 if (isset($element['autocomplete']['frequency'])) {
110 $frequency= $element['autocomplete']['frequency'];
111 }
112 if (isset($element['autocomplete']['characters'])) {
113 $characters= $element['autocomplete']['characters'];
114 }
115 $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
116 "<script type='text/javascript'>".
117 "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
118 "</script>";
120 $this->autocompleters[$tag]= $element['autocomplete'];
121 }
122 return $result;
123 }
126 function getCheckbox($element)
127 {
128 $tag= $element['tag'];
129 $checked= "";
130 if ($this->elementValues[$tag] == "true") {
131 $checked= " checked";
132 }
134 $result= "<input class='filter_checkbox' name='$tag' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
135 return $result;
136 }
139 function getCombobox($element)
140 {
141 $result= "<select name='".$element['tag']."' size='1' onClick='document.mainform.submit();'>";
143 // Fill with presets
144 foreach ($element['value'] as $value) {
145 $selected= "";
146 if ($this->elementValues[$element['tag']] == $value['key']) {
147 $selected= " selected";
148 }
150 // Handle translations
151 if (is_array($value['set'])) {
152 $li= null;
154 // Get language index if available
155 $lang= preg_replace('/_.*$/', '', $GLOBALS['t_language']);
156 $mapper= array();
157 foreach($value['set'] as $index => $lv){
158 if (preg_match('/_attr$/', $index) && isset($lv['xml:lang']) && $lv['xml:lang'] == $lang) {
159 $li= preg_replace('/_attr$/', '', $index);
160 if (isset($mapper[$li])) {
161 unset($mapper[$li]);
162 }
163 } else {
164 $mapper[$index]= $index;
165 }
166 }
168 // Use some default if no index is available
169 if (!$li) {
170 $li= array_shift($mapper);
171 }
173 $result.= "<option value='".$value['key']."'$selected>".$value['set'][$li]."</option>";
174 } else {
175 $result.= "<option value='".$value['key']."'$selected>".$value['set']."</option>";
176 }
177 }
179 // Use autocompleter for additional data
180 if (isset($element['autocomplete'])) {
181 $list= $this->getCompletitionList($element['autocomplete'], $element['tag']);
182 foreach ($list as $value) {
183 $selected= "";
184 if ($this->elementValues[$element['tag']] == $value) {
185 $selected= " selected";
186 }
187 $result.= "<option value='$value'$selected>$value</option>";
188 }
189 }
191 $result.= "</select>";
193 return $result;
194 }
197 function getCurrentBase()
198 {
199 if (isset($this->search->base) && (string)$this->search->scope != "auto") {
200 return false;
201 }
203 return $this->base;
204 }
207 function getCurrentScope()
208 {
209 if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
210 return (string)$this->search->scope;
211 }
213 return $this->scope;
214 }
217 function setBases($bases) {
218 $this->bases= $bases;
219 }
222 function setObjectStorage($storage) {
223 $this->objectStorage= $storage;
224 }
227 function setObjectBase($base) {
228 $this->objectBase= $base;
229 }
232 function setCategory($category) {
233 $this->category= $category;
234 }
237 function setCurrentBase($base) {
238 $this->base= $base;
239 }
242 function setCurrentScope($scope) {
243 $this->scope= $scope;
244 }
247 function renderBase()
248 {
249 $result= "<select name='currentMainBase' onChange='mainform.submit()' size='1'>";
251 foreach ($this->bases as $key=>$value) {
252 $selected= "";
253 if ($key == $this->base) {
254 $selected= " selected";
255 }
256 $result.= "<option value='".$key."'$selected>".$value."</option>";
257 }
258 $result.= "</select>";
260 return $result;
261 }
264 function renderAlphabet($columns= 10)
265 {
266 // Return pre-rendered alphabet if available
267 if ($this->alphabet) {
268 return ($this->alphabet);
269 }
271 $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
272 $alphabet= "";
273 $c= 0;
275 /* Fill cells with charaters */
276 for ($i= 0, $l= mb_strlen($characters, 'UTF8'); $i<$l; $i++){
277 if ($c == 0){
278 $alphabet.= "<tr>";
279 }
281 $ch = mb_substr($characters, $i, 1, "UTF8");
282 $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
283 validate($_GET['plug'])."&filter=".$ch."\"> ".$ch." </a></td>";
285 if ($c++ == $columns){
286 $alphabet.= "</tr>";
287 $c= 0;
288 }
289 }
291 /* Fill remaining cells */
292 while ($c++ <= $columns){
293 $alphabet.= "<td> </td>";
294 }
296 /* Save alphabet */
297 $this->alphabet= "<table width='100%'>$alphabet</table>";
299 return ($this->alphabet);
300 }
303 function renderApply()
304 {
305 return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
306 }
309 function renderScope()
310 {
311 $checked= $this->scope == "sub"?" checked":"";
312 return "<input type='checkbox' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked> "._("Search in subtrees");
313 }
316 function renderFilter()
317 {
318 $smarty= get_smarty();
319 $smarty->assign("ALPHABET", $this->renderAlphabet());
320 $smarty->assign("APPLY", $this->renderApply());
321 $smarty->assign("SCOPE", $this->renderScope());
322 $smarty->assign("BASE", $this->renderBase());
324 // Load template and replace elementsHtml[]
325 foreach ($this->elements as $tag => $element) {
326 $htmlCode= "";
327 switch ($element['type']) {
328 case "textfield":
329 $htmlCode = $this->getTextfield($element);
330 break;
332 case "checkbox":
333 $htmlCode = $this->getCheckbox($element);
334 break;
336 case "combobox":
337 $htmlCode = $this->getCombobox($element);
338 break;
340 default:
341 die ("Unknown element type specified!");
342 }
343 $smarty->assign("$tag", $htmlCode);
344 }
346 // Load template
347 return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
348 }
351 function query()
352 {
353 global $class_mapping;
354 $result= array();
356 // Go thru all queries and merge results
357 foreach ($this->query as $query) {
358 if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
359 die("No backend specified in search config.");
360 }
362 // Is backend available?
363 $backend= "filter".$query['backend'];
364 if (!isset($class_mapping["$backend"])) {
365 die("Invalid backend specified in search config.");
366 }
368 // Load filter and attributes
369 $filter= $query['filter'];
370 $attributes= $query['attribute'];
372 // Generate final filter
373 foreach ($this->elements as $tag => $element) {
374 if (!isset($element['set']) || !isset($element['unset'])) {
375 continue;
376 }
377 $e_set= is_array($element['set'])?"":$element['set'];
378 $e_unset= is_array($element['unset'])?"":$element['unset'];
380 if ($this->elementValues[$tag] == "") {
381 $e_unset= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_unset);
382 $filter= preg_replace("/\\$$tag/", $e_unset, $filter);
383 } else {
384 $e_set= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_set);
385 $filter= preg_replace("/\\$$tag/", $e_set, $filter);
386 }
387 }
389 $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
390 $this->category, $this->objectStorage, $this->objectBase));
391 }
394 return ($result);
395 }
398 function isValid()
399 {
400 foreach ($this->elements as $tag => $element) {
401 if (isset($element->regex)){
402 if (!preg_match('/'.(string)$element->regex.'/', $this->elementValues[$tag])){
403 return false;
404 }
405 }
406 }
407 return true;
408 }
411 function update()
412 {
414 /* React on alphabet links if needed */
415 if (isset($_GET['filter'])){
416 $s= mb_substr(validate($_GET['filter']), 0, 1, "UTF8")."*";
417 if ($s == "**"){
418 $s= "*";
419 }
420 foreach ($this->alphabetElements as $tag) {
421 $this->elementValues[$tag]= $s;
422 }
423 }
425 if (isset($_POST['FILTER_LOADED'])) {
426 // Load post values and adapt filter, base and scope accordingly - but
427 // only if we didn't get a _GET
428 foreach ($this->elements as $tag => $element) {
429 if (isset($_POST[$tag])){
430 $this->elementValues[$tag]= validate($_POST[$tag]);
431 } else {
432 $this->elementValues[$tag]= "";
433 }
434 }
435 }
437 // Save base
438 if (isset($_POST['BASE']) && $this->baseMode == "true") {
439 $base= validate($_POST['BASE']);
440 if (isset($this->bases[$base])) {
441 $this->base= $base;
442 }
443 }
445 // Save scope if needed
446 if ($this->scopeMode == "auto") {
447 $this->scope= isset($_POST['SCOPE'])?"sub":"one";
448 }
449 }
452 function getCompletitionList($config, $tag, $value="*")
453 {
454 global $class_mapping;
455 $res= array();
457 // Is backend available?
458 $backend= "filter".$config['backend'];
459 if (!isset($class_mapping["$backend"])) {
460 die("Invalid backend specified in search config.");
461 }
463 // Load filter and attributes
464 $filter= $config['filter'];
465 $attributes= $config['attribute'];
466 if (!is_array($attributes)) {
467 $attributes= array($attributes);
468 }
470 // Make filter
471 $filter= preg_replace("/\\$$tag/", normalizeLDAP($value), $filter);
472 if (isset($config['base']) && isset($config['scope'])
473 && isset($config['category']) && isset($config['objectbase']) ) {
474 $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
475 $config["category"], $config["objectbase"]);
476 } else {
477 $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
478 $this->category, $this->objectStorage, $this->objectBase);
479 }
481 foreach ($result as $entry) {
482 foreach ($attributes as $attribute) {
483 if (is_array($entry[$attribute])) {
484 for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
485 $res[]= $entry[$attribute][$i];
486 }
487 } else {
488 $res[]= $entry[$attribute];
489 }
490 }
491 }
493 return $res;
494 }
497 function processAutocomplete()
498 {
499 global $class_mapping;
500 $result= array();
502 foreach ($this->autocompleters as $tag => $config) {
503 if(isset($_POST[$tag])){
504 $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
506 echo '<ul>';
507 foreach ($result as $entry) {
508 echo '<li>'.$entry.'</li>';
509 }
511 echo '</ul>';
512 }
514 }
515 }
517 }
519 ?>