ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilSearchGUI.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once 'Services/Search/classes/class.ilSearchBaseGUI.php';
5
6
7
23{
24 protected $search_cache = null;
25
29 var $type;
30
31
36 public function __construct()
37 {
38 global $ilUser, $lng;
39
40 $lng->loadLanguageModule("search");
41
42 // put form values into "old" post variables
44 $this->form->checkInput();
45
46 $new_search = isset($_POST['cmd']['performSearch']) ? true : false;
47
48 $enabled_types = ilSearchSettings::getInstance()->getEnabledLuceneItemFilterDefinitions();
49 foreach($enabled_types as $type => $pval)
50 {
51 if($_POST['filter_type'][$type] == 1)
52 {
53 $_POST["search"]["details"][$type] = $_POST['filter_type'][$type];
54 }
55 }
56
57 $_POST["search"]["string"] = $_POST["term"];
58 $_POST["search"]["combination"] = $_POST["combination"];
59 $_POST["search"]["type"] = $_POST["type"];
60 $_SESSION['search_root'] = $_POST["area"];
61
62 $this->root_node = $_SESSION['search_root'] ? $_SESSION['search_root'] : ROOT_FOLDER_ID;
63 $this->setType($_POST['search']['type'] ? $_POST['search']['type'] : $_SESSION['search']['type']);
64 $this->setCombination($_POST['search']['combination'] ? $_POST['search']['combination'] : $_SESSION['search']['combination']);
65 $this->setString($_POST['search']['string'] ? $_POST['search']['string'] : $_SESSION['search']['string']);
66 #$this->setDetails($_POST['search']['details'] ? $_POST['search']['details'] : $_SESSION['search']['details']);
67 $this->setDetails($new_search ? $_POST['search']['details'] : $_SESSION['search']['details']);
68 parent::__construct();
69 }
70
71
76 public function executeCommand()
77 {
78 global $rbacsystem, $ilCtrl;
79
80
81
82 $next_class = $this->ctrl->getNextClass($this);
83 $cmd = $this->ctrl->getCmd();
84
85 switch($next_class)
86 {
87 case "ilpropertyformgui":
88 //$this->initStandardSearchForm(ilSearchBaseGUI::SEARCH_FORM_STANDARD);
89 $form = $this->getSearchAreaForm();
90 $this->prepareOutput();
91 $ilCtrl->setReturn($this, 'storeRoot');
92 return $ilCtrl->forwardCommand($form);
93
94 case 'ilobjectcopygui':
95 $this->prepareOutput();
96 $this->ctrl->setReturn($this,'');
97 include_once './Services/Object/classes/class.ilObjectCopyGUI.php';
98 $cp = new ilObjectCopyGUI($this);
99 $this->ctrl->forwardCommand($cp);
100 break;
101
102 default:
103 $this->initUserSearchCache();
104 if(!$cmd)
105 {
106 $cmd = "showSavedResults";
107 }
108 $this->prepareOutput();
109 $this->handleCommand($cmd);
110 break;
111 }
112 return true;
113 }
114
119 function setType($a_type)
120 {
121 $_SESSION['search']['type'] = $this->type = $a_type;
122 }
123 function getType()
124 {
125 return $this->type ? $this->type : ilSearchBaseGUI::SEARCH_FAST;
126 }
131 function setCombination($a_combination)
132 {
133 $_SESSION['search']['combination'] = $this->combination = $a_combination;
134 }
135 function getCombination()
136 {
137 return $this->combination ? $this->combination : ilSearchBaseGUI::SEARCH_OR;
138 }
143 function setString($a_str)
144 {
145 $_SESSION['search']['string'] = $this->string = $a_str;
146 }
147 function getString()
148 {
149 return $this->string;
150 }
155 function setDetails($a_details)
156 {
157 $_SESSION['search']['details'] = $this->details = $a_details;
158 }
159 function getDetails()
160 {
161 return $this->details ? $this->details : array();
162 }
163
164
165 function getRootNode()
166 {
167 return $this->root_node ? $this->root_node : ROOT_FOLDER_ID;
168 }
169 function setRootNode($a_node_id)
170 {
171 $_SESSION['search_root'] = $this->root_node = $a_node_id;
172 }
173
174
175 function remoteSearch()
176 {
177 $this->setString(ilUtil::stripSlashes($_POST['queryString']));
178 $this->setRootNode((int) $_POST['root_id']);
179 $this->performSearch();
180
181 }
182
186 protected function storeRoot()
187 {
188 $form = $this->getSearchAreaForm();
189
190 $this->root_node = $form->getItemByPostVar('area')->getValue();
191 $this->search_cache->setRoot($this->root_node);
192 $this->search_cache->save();
193 $this->search_cache->deleteCachedEntries();
194
195 include_once './Services/Object/classes/class.ilSubItemListGUI.php';
197
198 $this->performSearch();
199 }
200
204 public function autoComplete()
205 {
206 if((int) $_REQUEST['search_type'] == -1)
207 {
208 $a_fields = array('login','firstname','lastname','email');
209 $result_field = 'login';
210
211 // Starting user autocomplete search
212 include_once './Services/User/classes/class.ilUserAutoComplete.php';
213 $auto = new ilUserAutoComplete();
214
215
216 $auto->setMoreLinkAvailable(true);
217 $auto->setSearchFields($a_fields);
218 $auto->setResultField($result_field);
219 $auto->enableFieldSearchableCheck(true);
220 $auto->setUserLimitations(true);
221
222 $res = $auto->getList($_REQUEST['term']);
223
224 $res_obj = json_decode($res);
225
226 ilLoggerFactory::getLogger('sea')->debug($res);
227
228
229 ilLoggerFactory::getLogger('sea')->dump($res_obj->items, ilLogLevel::DEBUG);
230 if(is_array($res_obj->items))
231 {
232 echo json_encode($res_obj->items);
233 exit;
234 }
235
236 }
237 else
238 {
239 $q = $_REQUEST["term"];
240 include_once("./Services/Search/classes/class.ilSearchAutoComplete.php");
242 ilLoggerFactory::getLogger('sea')->dump(json_decode($list));
243 echo $list;
244 exit;
245 }
246 }
247
248 function showSearch()
249 {
250 global $ilLocator, $ilCtrl, $lng;
251
252 // include js needed
253 include_once("./Services/UIComponent/Overlay/classes/class.ilOverlayGUI.php");
255 $this->tpl->addJavascript("./Services/Search/js/Search.js");
256
257 include_once("./Services/UIComponent/Glyph/classes/class.ilGlyphGUI.php");
258
259 $this->tpl->addBlockFile('ADM_CONTENT','adm_content','tpl.search.html','Services/Search');
260 $this->tpl->setVariable("FORM_ACTION", $ilCtrl->getFormAction($this,'performSearch'));
261 $this->tpl->setVariable("TERM", ilUtil::prepareFormOutput($this->getString()));
262 include_once("./Services/UIComponent/Button/classes/class.ilSubmitButton.php");
264 $btn->setCommand("performSearch");
265 $btn->setCaption("search");
266 $this->tpl->setVariable("SUBMIT_BTN",$btn->render());
267 $this->tpl->setVariable("TXT_OPTIONS", $lng->txt("options"));
268 $this->tpl->setVariable("ARR_IMG", ilGlyphGUI::get(ilGlyphGUI::CARET));
269 $this->tpl->setVariable("TXT_COMBINATION", $lng->txt("search_term_combination"));
270 $this->tpl->setVariable('TXT_COMBINATION_DEFAULT', ilSearchSettings::getInstance()->getDefaultOperator() == ilSearchSettings::OPERATOR_AND ? $lng->txt('search_all_words') : $lng->txt('search_any_word'));
271
272 if (ilSearchSettings::getInstance()->isLuceneItemFilterEnabled())
273 {
274 $this->tpl->setCurrentBlock("type_sel");
275 $this->tpl->setVariable('TXT_TYPE_DEFAULT',$lng->txt("search_fast_info"));
276 $this->tpl->setVariable("TXT_TYPE", $lng->txt("search_type"));
278 $this->tpl->setVariable("ARR_IMGT", ilGlyphGUI::get(ilGlyphGUI::CARET));
279 $this->tpl->setVariable("FORM", $this->form->getHTML());
280 $this->tpl->parseCurrentBlock();
281 }
282
283 if(ilSearchSettings::getInstance()->isDateFilterEnabled())
284 {
285 // begin-patch creation_date
286 $this->tpl->setVariable('TXT_FILTER_BY_CDATE',$this->lng->txt('search_filter_cd'));
287 $this->tpl->setVariable('TXT_CD_OFF',$this->lng->txt('search_off'));
288 $this->tpl->setVariable('FORM_CD',$this->getCreationDateForm()->getHTML());
289 $this->tpl->setVariable("ARR_IMG_CD", ilGlyphGUI::get(ilGlyphGUI::CARET));
290 // end-patch creation_date
291 }
292
293
294 $this->tpl->setVariable("TXT_AREA", $lng->txt("search_area"));
295
296 // search area form
297 $this->tpl->setVariable('SEARCH_AREA_FORM', $this->getSearchAreaForm()->getHTML());
298
299 return true;
300 }
301
303 {
304 global $ilUser;
305
306 // Read old result sets
307 include_once 'Services/Search/classes/class.ilSearchResult.php';
308
309 $result_obj = new ilSearchResult($ilUser->getId());
310 $result_obj->read();
311 $result_obj->filterResults($this->getRootNode());
312
313 $this->showSearch();
314
315 // Show them
316 if(count($result_obj->getResults()))
317 {
318 $this->addPager($result_obj,'max_page');
319
320 include_once './Services/Search/classes/class.ilSearchResultPresentation.php';
322 $presentation->setResults($result_obj->getResultsForPresentation());
323 $presentation->setSubitemIds($result_obj->getSubitemIds());
324 $presentation->setPreviousNext($this->prev_link, $this->next_link);
325 #$presentation->setSearcher($searcher);
326
327 if($presentation->render())
328 {
329// $this->tpl->setVariable('SEARCH_RESULTS',$presentation->getHTML());
330 $this->tpl->setVariable('RESULTS_TABLE',$presentation->getHTML(true));
331 }
332 }
333
334 return true;
335 }
336
337
341 function performSearch()
342 {
343 global $ilUser;
344
345 if(!isset($_GET['page_number']) and $this->search_mode != 'in_results' )
346 {
347 unset($_SESSION['max_page']);
348 $this->search_cache->deleteCachedEntries();
349 }
350
351 if($this->getType() == ilSearchBaseGUI::SEARCH_DETAILS and !$this->getDetails())
352 {
353 ilUtil::sendInfo($this->lng->txt('search_choose_object_type'));
354 $this->showSearch();
355 return false;
356 }
357
358 // Step 1: parse query string
359 if(!is_object($query_parser =& $this->__parseQueryString()))
360 {
361 ilUtil::sendInfo($query_parser);
362 $this->showSearch();
363
364 return false;
365 }
366 // Step 2: perform object search. Get an ObjectSearch object via factory. Depends on fulltext or like search type.
367 $result =& $this->__searchObjects($query_parser);
368
369 // Step 3: perform meta keyword search. Get an MetaDataSearch object.
370 $result_meta =& $this->__searchMeta($query_parser,'keyword');
371 $result->mergeEntries($result_meta);
372
373 $result_meta =& $this->__searchMeta($query_parser,'contribute');
374 $result->mergeEntries($result_meta);
375
376 $result_meta =& $this->__searchMeta($query_parser,'title');
377 $result->mergeEntries($result_meta);
378
379 $result_meta =& $this->__searchMeta($query_parser,'description');
380 $result->mergeEntries($result_meta);
381
382 // Perform details search in object specific tables
384 {
385 $result = $this->__performDetailsSearch($query_parser,$result);
386 }
387 // Step 5: Search in results
388 if($this->search_mode == 'in_results')
389 {
390 include_once 'Services/Search/classes/class.ilSearchResult.php';
391
392 $old_result_obj = new ilSearchResult($ilUser->getId());
393 $old_result_obj->read();
394
395 $result->diffEntriesFromResult($old_result_obj);
396 }
397
398
399 // Step 4: merge and validate results
400 $result->filter($this->getRootNode(),$query_parser->getCombination() == 'and');
401 $result->save();
402 $this->showSearch();
403
404 if(!count($result->getResults()))
405 {
406 ilUtil::sendInfo($this->lng->txt('search_no_match'));
407 }
408
409 if($result->isLimitReached())
410 {
411 #$message = sprintf($this->lng->txt('search_limit_reached'),$this->settings->getMaxHits());
412 #ilUtil::sendInfo($message);
413 }
414
415 // Step 6: show results
416 $this->addPager($result,'max_page');
417
418 include_once './Services/Search/classes/class.ilSearchResultPresentation.php';
420 $presentation->setResults($result->getResultsForPresentation());
421 $presentation->setSubitemIds($result->getSubitemIds());
422 $presentation->setPreviousNext($this->prev_link, $this->next_link);
423
424 if($presentation->render())
425 {
426// $this->tpl->setVariable('SEARCH_RESULTS',$presentation->getHTML());
427 $this->tpl->setVariable('RESULTS_TABLE',$presentation->getHTML(true));
428 }
429
430 return true;
431 }
432
433
434
435 function prepareOutput()
436 {
437 global $ilTabs, $ilHelp;
438
439 parent::prepareOutput();
440
441 $ilHelp->setScreenIdComponent("src");
442
443 $ilTabs->addTab("search", $this->lng->txt("search"),
444 $this->ctrl->getLinkTarget($this));
445
446 if (!$this->settings->getHideAdvancedSearch())
447 {
448 $ilTabs->addTab("adv_search", $this->lng->txt("search_advanced"),
449 $this->ctrl->getLinkTargetByClass('iladvancedsearchgui'));
450 }
451
452 $ilTabs->activateTab("search");
453 }
454
455 // PRIVATE
456 function &__performDetailsSearch(&$query_parser,&$result)
457 {
458 foreach($this->getDetails() as $type => $enabled)
459 {
460 if(!$enabled)
461 {
462 continue;
463 }
464
465 switch($type)
466 {
467 case 'crs':
468 $crs_search = ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
469 $crs_search->setFilter(array('crs'));
470 $result->mergeEntries($crs_search->performSearch());
471 break;
472
473 case 'grp':
474 $grp_search = ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
475 $grp_search->setFilter(array('grp'));
476 $result->mergeEntries($grp_search->performSearch());
477 break;
478
479 case 'lms':
480 $content_search =& ilObjectSearchFactory::_getLMContentSearchInstance($query_parser);
481 $content_search->setFilter($this->__getFilter());
482 $result->mergeEntries($content_search->performSearch());
483 break;
484
485 case 'frm':
486 $forum_search =& ilObjectSearchFactory::_getForumSearchInstance($query_parser);
487 $forum_search->setFilter($this->__getFilter());
488 $result->mergeEntries($forum_search->performSearch());
489 break;
490
491 case 'glo':
492 // Glossary term definition pages
493 $gdf_search =& ilObjectSearchFactory::_getLMContentSearchInstance($query_parser);
494 $gdf_search->setFilter(array('gdf'));
495 $result->mergeEntries($gdf_search->performSearch());
496 // Glossary terms
497 $gdf_term_search =& ilObjectSearchFactory::_getGlossaryDefinitionSearchInstance($query_parser);
498 $result->mergeEntries($gdf_term_search->performSearch());
499 break;
500
501 case 'exc':
502 $exc_search =& ilObjectSearchFactory::_getExerciseSearchInstance($query_parser);
503 $exc_search->setFilter($this->__getFilter());
504 $result->mergeEntries($exc_search->performSearch());
505 break;
506
507 case 'mcst':
508 $mcst_search =& ilObjectSearchFactory::_getMediaCastSearchInstance($query_parser);
509 $result->mergeEntries($mcst_search->performSearch());
510 break;
511
512 case 'tst':
513 $tst_search =& ilObjectSearchFactory::_getTestSearchInstance($query_parser);
514 $tst_search->setFilter($this->__getFilter());
515 $result->mergeEntries($tst_search->performSearch());
516 break;
517
518 case 'mep':
519 $mep_search =& ilObjectSearchFactory::_getMediaPoolSearchInstance($query_parser);
520 $mep_search->setFilter($this->__getFilter());
521 $result->mergeEntries($mep_search->performSearch());
522
523 // Mob keyword search
524 $mob_search = ilObjectSearchFactory::_getMediaPoolSearchInstance($query_parser);
525 $mob_search->setFilter($this->__getFilter());
526 $result->mergeEntries($mob_search->performKeywordSearch());
527
528 break;
529
530 case 'wiki':
531 $wiki_search =& ilObjectSearchFactory::_getWikiContentSearchInstance($query_parser);
532 $wiki_search->setFilter($this->__getFilter());
533 $result->mergeEntries($wiki_search->performSearch());
534
535 /*$result_meta =& $this->__searchMeta($query_parser,'title');
536 $result->mergeEntries($result_meta);
537 $result_meta =& $this->__searchMeta($query_parser,'description');
538 $result->mergeEntries($result_meta);*/
539 break;
540
541 }
542 }
543 return $result;
544 }
545
552 {
553 include_once 'Services/Search/classes/class.ilQueryParser.php';
554
555 $query_parser = new ilQueryParser(ilUtil::stripSlashes($this->getString()));
556 $query_parser->setCombination($this->getCombination());
557 $query_parser->parse();
558
559 if(!$query_parser->validate())
560 {
561 return $query_parser->getMessage();
562 }
563 return $query_parser;
564 }
570 function &__searchObjects(&$query_parser)
571 {
572 include_once 'Services/Search/classes/class.ilObjectSearchFactory.php';
573
574 $obj_search =& ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
576 {
577 $obj_search->setFilter($this->__getFilter());
578 }
579
580 $this->parseCreationFilter($obj_search);
581 return $obj_search->performSearch();
582 }
583
584 public function parseCreationFilter(ilObjectSearch $search)
585 {
586 $options = $this->getSearchCache()->getCreationFilter();
587
588 if(!$options['enabled'])
589 {
590 return TRUE;
591 }
592 $limit = new ilDate($options['date'],IL_CAL_UNIX);
593 $search->setCreationDateFilterDate($limit);
594
595 switch($options['ontype'])
596 {
597 case 1:
599 break;
600
601 case 2:
603 break;
604
605 case 3:
607 break;
608 }
609
610 return TRUE;
611 }
612
613
619 function &__searchMeta(&$query_parser,$a_type)
620 {
621 include_once 'Services/Search/classes/class.ilObjectSearchFactory.php';
622
623 $meta_search =& ilObjectSearchFactory::_getMetaDataSearchInstance($query_parser);
625 {
626 $meta_search->setFilter($this->__getFilter());
627 }
628 switch($a_type)
629 {
630 case 'keyword':
631 $meta_search->setMode('keyword');
632 break;
633
634 case 'contribute':
635 $meta_search->setMode('contribute');
636 break;
637
638 case 'title':
639 $meta_search->setMode('title');
640 break;
641
642 case 'description':
643 $meta_search->setMode('description');
644 break;
645 }
646 return $meta_search->performSearch();
647 }
653 function __getFilter()
654 {
656 {
657 return false;
658 }
659
660 foreach($this->getDetails() as $key => $detail_type)
661 {
662 if(!$detail_type)
663 {
664 continue;
665 }
666
667 switch($key)
668 {
669 case 'lms':
670 $filter[] = 'lm';
671 $filter[] = 'dbk';
672 $filter[] = 'pg';
673 $filter[] = 'st';
674 $filter[] = 'sahs';
675 $filter[] = 'htlm';
676 break;
677
678 case 'frm':
679 $filter[] = 'frm';
680 break;
681
682 case 'glo':
683 $filter[] = 'glo';
684 break;
685
686 case 'exc':
687 $filter[] = 'exc';
688 break;
689
690 case 'mcst':
691 $filter[] = 'mcst';
692 break;
693
694 case 'tst':
695 $filter[] = 'tst';
696 $filter[] = 'svy';
697 $filter[] = 'qpl';
698 $filter[] = 'spl';
699 break;
700
701 case 'mep':
702 $filter[] = 'mep';
703 $filter[] = 'mob';
704 break;
705
706 case 'fil':
707 $filter[] = 'file';
708 break;
709
710 case 'wiki':
711 $filter[] = 'wpg';
712 break;
713
714 default:
715 $filter[] = $key;
716 }
717 }
718 return $filter ? $filter : array();
719 }
720
727 protected function initUserSearchCache()
728 {
729 global $ilUser;
730
731 include_once('Services/Search/classes/class.ilUserSearchCache.php');
732 $this->search_cache = ilUserSearchCache::_getInstance($ilUser->getId());
733 $this->search_cache->switchSearchType(ilUserSearchCache::DEFAULT_SEARCH);
734
735 if($_GET['page_number'])
736 {
737 $this->search_cache->setResultPageNumber((int) $_GET['page_number']);
738 }
739 if(isset($_POST['cmd']['performSearch']))
740 {
741 $this->search_cache->setQuery(ilUtil::stripSlashes($_POST['term']));
742 $this->search_cache->setCreationFilter($this->loadCreationFilter());
743 $this->search_cache->save();
744 }
745 }
746
747}
748?>
$result
$_GET["client_id"]
$_POST["username"]
$_SESSION["AccountId"]
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_UNIX
Class for single dates.
static get($a_glyph, $a_text="")
Get glyph html.
static getLogger($a_component_id)
Get component logger.
GUI class for the workflow of copying objects.
static _getMetaDataSearchInstance($query_parser)
get reference of ilFulltext/LikeMetaDataSearch.
static _getMediaPoolSearchInstance($query_parser)
get reference of ilFulltextMediapoolSearch
static _getLMContentSearchInstance($query_parser)
get reference of ilFulltextLMContentSearch
static _getTestSearchInstance($query_parser)
get reference of ilFulltextTestSearch
static _getGlossaryDefinitionSearchInstance($query_parser)
get reference of ilFulltextGlossaryDefinitionSearch
static _getObjectSearchInstance($query_parser)
get reference of ilFulltext/LikeObjectSearch.
static _getExerciseSearchInstance($query_parser)
get reference of ilFulltextExerciseSearch
static _getForumSearchInstance($query_parser)
get reference of ilFulltextForumSearch
static _getWikiContentSearchInstance($query_parser)
get reference of ilFulltextWikiContentSearch
setCreationDateFilterDate(ilDate $day)
Set creation date filter.
setCreationDateFilterOperator($a_operator)
static initJavascript()
Init javascript.
static getList($a_str)
Get completion list.
initStandardSearchForm($a_mode)
Init standard search form.
addPager($result, $a_session_key)
Add Pager.
getSearchCache()
Get user search cache.
getSearchAreaForm()
Init standard search form.
loadCreationFilter()
Load creation date filter.
handleCommand($a_cmd)
Handle command.
Class ilSearchGUI.
setString($a_str)
Set/get search string @access public.
performSearch()
Perform search.
& __searchObjects(&$query_parser)
Search in obect title,desctiption.
__construct()
Constructor @access public.
setCombination($a_combination)
Set/get combination of search ('and' or 'or') @access public.
executeCommand()
Control @access public.
setDetails($a_details)
Set/get details (object types for details search) @access public.
setType($a_type)
Set/get type of search (detail or 'fast' search) @access public.
setRootNode($a_node_id)
parseCreationFilter(ilObjectSearch $search)
storeRoot()
Store new root node.
& __searchMeta(&$query_parser, $a_type)
Search in object meta data (keyword)
autoComplete()
Data resource for autoComplete.
__getFilter()
Get object type for filter (If detail search is enabled)
& __performDetailsSearch(&$query_parser, &$result)
initUserSearchCache()
Init user search cache.
& __parseQueryString()
parse query string, using query parser instance
Presentation of search results using object list gui.
static resetDetails()
reset details As long as static::resetDetails is not possible this method is final
static getInstance()
Factory.
Auto completion class for user lists.
static _getInstance($a_usr_id)
Get singleton instance.
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
global $ilCtrl
Definition: ilias.php:18
$cmd
Definition: sahs_server.php:35
settings()
Definition: settings.php:2
if(!is_array($argv)) $options
$ilUser
Definition: imgupload.php:18
$a_type
Definition: workflow.php:93