Initial revision
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_fullsearch.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 Kasper Skårhøj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Class used in module tools/dbint (advanced search) and which may hold code specific for that module
29 * However the class has a general principle in it which may be used in the web/export module.
30 *
31 * @author Kasper Skårhøj <kasper@typo3.com>
32 * @package TYPO3
33 * @subpackage t3lib
34 */
35
36
37 class t3lib_fullsearch {
38 var $storeList = "search_query_smallparts,queryConfig,queryTable,queryFields,queryLimit,queryOrder,queryOrderDesc,queryOrder2,queryOrder2Desc,queryGroup,search_query_makeQuery";
39 var $downloadScript = "index.php";
40 var $formW=48;
41 var $noDownloadB=0;
42
43 function form() {
44 $out='
45 Search Word:<BR>
46 <input type="text" name="SET[sword]" value="'.$GLOBALS["SOBE"]->MOD_SETTINGS["sword"].'"'.$GLOBALS["TBE_TEMPLATE"]->formWidth(20).'><input type="submit" name="submit" value="Search All Records">
47 ';
48
49 return $out;
50 }
51 function makeStoreControl() {
52 // Load/Save
53 $storeArray = $this->initStoreArray();
54 $cur="";
55
56 // Store Array:
57 $opt=array();
58 reset($storeArray);
59 while(list($k,$v)=each($storeArray)) {
60 $opt[]='<option value="'.$k.'"'.(!strcmp($cur,$v)?" selected":"").'>'.htmlspecialchars($v).'</option>';
61 }
62
63 // Actions:
64 if (t3lib_extMgm::isLoaded("sys_action")) {
65 $query = "SELECT * FROM sys_action WHERE type=2 ORDER BY title";
66 $res = mysql(TYPO3_db,$query);
67 if (mysql_num_rows($res)) {
68 $opt[]='<option value="0">__Save to Action:__</option>';
69 while($row=mysql_fetch_assoc($res)) {
70 $opt[]='<option value="-'.$row["uid"].'"'.(!strcmp($cur,"-".$row["uid"])?" selected":"").'>'.htmlspecialchars($row["title"]." [".$row["uid"]."]").'</option>';
71 }
72 }
73 }
74
75 $TDparams=' nowrap bgcolor="'.$GLOBALS["TBE_TEMPLATE"]->bgColor4.'"';
76 $tmpCode='
77 <table border=0 cellpadding=3 cellspacing=1>
78 <tr'.$TDparams.'><td><select name="storeControl[STORE]" onChange="document.forms[0][\'storeControl[title]\'].value= this.options[this.selectedIndex].value!=0 ? this.options[this.selectedIndex].text : \'\';">'.implode(chr(10),$opt).'</select><input type="submit" name="storeControl[LOAD]" value="Load"></td></tr>
79 <tr'.$TDparams.'><td nowrap><input name="storeControl[title]" value="" type="text" max=80'.$GLOBALS["SOBE"]->doc->formWidth().'><input type="submit" name="storeControl[SAVE]" value="Save" onClick="if (document.forms[0][\'storeControl[STORE]\'].options[document.forms[0][\'storeControl[STORE]\'].selectedIndex].value<0) return confirm(\'Are you sure you want to overwrite the existing query in this action?\');"><input type="submit" name="storeControl[REMOVE]" value="Remove"></td></tr>
80 </table>
81 ';
82 return $tmpCode;
83 }
84 function initStoreArray() {
85 $storeArray=array(
86 "0" => "[New]"
87 );
88
89 $savedStoreArray = unserialize($GLOBALS["SOBE"]->MOD_SETTINGS["storeArray"]);
90
91 if (is_array($savedStoreArray)) {
92 $storeArray = array_merge($storeArray,$savedStoreArray);
93 }
94 return $storeArray;
95 }
96 function cleanStoreQueryConfigs($storeQueryConfigs,$storeArray) {
97 if (is_array($storeQueryConfigs)) {
98 reset($storeQueryConfigs);
99 while(list($k,$v)=each($storeQueryConfigs)) {
100 if (!isset($storeArray[$k])) unset($storeQueryConfigs[$k]);
101 }
102 }
103 return $storeQueryConfigs;
104 }
105 function addToStoreQueryConfigs($storeQueryConfigs,$index) {
106 $keyArr = explode(",",$this->storeList);
107 reset($keyArr);
108 $storeQueryConfigs[$index]=array();
109 while(list(,$k)=each($keyArr)) {
110 $storeQueryConfigs[$index][$k]=$GLOBALS["SOBE"]->MOD_SETTINGS[$k];
111 }
112 return $storeQueryConfigs;
113 }
114 function saveQueryInAction($uid) {
115 if (t3lib_extMgm::isLoaded("sys_action")) {
116 $keyArr = explode(",",$this->storeList);
117 reset($keyArr);
118 $saveArr=array();
119 while(list(,$k)=each($keyArr)) {
120 $saveArr[$k]=$GLOBALS["SOBE"]->MOD_SETTINGS[$k];
121 }
122
123 $dA=array();
124 $qOK=0;
125 // Show query
126 if ($saveArr["queryTable"]) {
127 $qGen = t3lib_div::makeInstance("t3lib_queryGenerator");
128 $qGen->init("queryConfig",$saveArr["queryTable"]);
129 $qGen->makeSelectorTable($saveArr);
130
131 $qGen->enablePrefix=1;
132 $qString = $qGen->getQuery($qGen->queryConfig);
133 $qCount = "SELECT count(*) FROM ".$qGen->table." WHERE ".$qString.t3lib_BEfunc::deleteClause($qGen->table);
134 $qSelect = $qGen->getSelectQuery($qString);
135
136 $res = @mysql(TYPO3_db,$qCount);
137 if (!mysql_error()) {
138 $dA["t2_data"] = serialize(array(
139 "qC"=>$saveArr,
140 "qCount" => $qCount,
141 "qSelect" => $qSelect,
142 "qString" => $qString
143 ));
144 // debug(unserialize($dA["t2_data"]));
145 $qOK=1;
146 }
147 }
148 //$this->tableWrap($qExplain)
149
150 $query = t3lib_BEfunc::DBcompileUpdate("sys_action","uid=".intval($uid),$dA);
151 $res = mysql(TYPO3_db,$query);
152 return $qOK;
153 }
154 }
155 function loadStoreQueryConfigs($storeQueryConfigs,$storeIndex,$writeArray) {
156 if ($storeQueryConfigs[$storeIndex]) {
157 $keyArr = explode(",",$this->storeList);
158 reset($keyArr);
159 while(list(,$k)=each($keyArr)) {
160 $writeArray[$k]=$storeQueryConfigs[$storeIndex][$k];
161 }
162 }
163 return $writeArray;
164 }
165 function procesStoreControl() {
166 $storeArray = $this->initStoreArray();
167 $storeQueryConfigs = unserialize($GLOBALS["SOBE"]->MOD_SETTINGS["storeQueryConfigs"]);
168
169 $storeControl = t3lib_div::GPvar("storeControl");
170 $storeIndex = intval($storeControl["STORE"]);
171 $saveStoreArray=0;
172 $writeArray=array();
173 if (is_array($storeControl)) {
174 $storeControl = t3lib_div::slashArray($storeControl,"strip");
175 if ($storeControl["LOAD"]) {
176 if ($storeIndex>0) {
177 $writeArray=$this->loadStoreQueryConfigs($storeQueryConfigs,$storeIndex,$writeArray);
178 $saveStoreArray=1;
179 $msg="'".$storeArray[$storeIndex]."' query loaded!";
180 } elseif ($storeIndex<0 && t3lib_extMgm::isLoaded("sys_action")) {
181 $actionRecord=t3lib_BEfunc::getRecord("sys_action",abs($storeIndex));
182 if (is_array($actionRecord)) {
183 $dA = unserialize($actionRecord["t2_data"]);
184 $dbSC=array();
185 if (is_array($dA["qC"])) {
186 $dbSC[0] = $dA["qC"];
187 }
188 $writeArray=$this->loadStoreQueryConfigs($dbSC,"0",$writeArray);
189 $saveStoreArray=1;
190 $acTitle=htmlspecialchars($actionRecord["title"]);
191 $msg="Query from action '".$acTitle."' loaded!";
192 }
193 }
194 } elseif ($storeControl["SAVE"]) {
195 if ($storeIndex<0) {
196 $qOK = $this->saveQueryInAction(abs($storeIndex));
197 if ($qOK) {
198 $msg="Query OK and saved.";
199 } else {
200 $msg="No query saved!";
201 }
202 } else {
203 if (trim($storeControl["title"])) {
204 if ($storeIndex>0) {
205 $storeArray[$storeIndex]=$storeControl["title"];
206 } else {
207 $storeArray[]=$storeControl["title"];
208 end($storeArray);
209 $storeIndex=key($storeArray);
210 }
211 $storeQueryConfigs=$this->addToStoreQueryConfigs($storeQueryConfigs,$storeIndex);
212 $saveStoreArray=1;
213 $msg="'".$storeArray[$storeIndex]."' query saved!";
214 }
215 }
216 } elseif ($storeControl["REMOVE"]) {
217 if ($storeIndex>0) {
218 $msg="'".$storeArray[$storeControl["STORE"]]."' query entry removed!";
219 unset($storeArray[$storeControl["STORE"]]); // Removing
220 $saveStoreArray=1;
221 }
222 }
223 }
224 if ($saveStoreArray) {
225 unset($storeArray[0]); // making sure, index 0 is not set!
226 $writeArray["storeArray"]=serialize($storeArray);
227 $writeArray["storeQueryConfigs"]=serialize($this->cleanStoreQueryConfigs($storeQueryConfigs,$storeArray));
228 $GLOBALS["SOBE"]->MOD_SETTINGS = t3lib_BEfunc::getModuleData($GLOBALS["SOBE"]->MOD_MENU, $writeArray, $GLOBALS["SOBE"]->MCONF["name"], "ses");
229 }
230 return $msg;
231 }
232 function queryMaker() {
233 global $TCA;
234
235 $msg=$this->procesStoreControl();
236
237 $output.= $GLOBALS["SOBE"]->doc->section('Load/Save Query',$this->makeStoreControl(),0,1);
238 if ($msg) {
239 $output.= $GLOBALS["SOBE"]->doc->section('','<font color=red><strong>'.$msg.'</strong></font>');
240 }
241 $output.= $GLOBALS["SOBE"]->doc->spacer(20);
242
243
244 // Query Maker:
245 $qGen = t3lib_div::makeInstance("t3lib_queryGenerator");
246 $qGen->init("queryConfig",$GLOBALS["SOBE"]->MOD_SETTINGS["queryTable"]);
247 $tmpCode=$qGen->makeSelectorTable($GLOBALS["SOBE"]->MOD_SETTINGS);
248 $output.= $GLOBALS["SOBE"]->doc->section('Make query',$tmpCode,0,1);
249
250 $mQ = $GLOBALS["SOBE"]->MOD_SETTINGS["search_query_makeQuery"];
251
252 // Make form elements:
253 if ($qGen->table && is_array($TCA[$qGen->table])) {
254 if ($mQ) {
255 // Show query
256 $qGen->enablePrefix=1;
257 $qString = $qGen->getQuery($qGen->queryConfig);
258 // debug($qGen->queryConfig);
259
260 switch($mQ) {
261 case "count":
262 $qExplain = "SELECT count(*) FROM ".$qGen->table." WHERE ".$qString.t3lib_BEfunc::deleteClause($qGen->table);
263 break;
264 default:
265 // $qExplain = "SELECT uid,pid,".$TCA[$qGen->table]["ctrl"]["label"]." FROM ".$qGen->table." WHERE ".$qString.t3lib_BEfunc::deleteClause($qGen->table)." LIMIT 100";
266 $qExplain = $qGen->getSelectQuery($qString);
267 if ($mQ=="explain") {
268 $qExplain="EXPLAIN ".$qExplain;
269 }
270 break;
271 }
272
273 $output.= $GLOBALS["SOBE"]->doc->section('SQL query',$this->tableWrap($qExplain),0,1);
274
275 $res = @mysql(TYPO3_db,$qExplain);
276 if (mysql_error()) {
277 $out.="<BR><strong>Error:</strong><BR><font color=red><strong>".mysql_error()."</strong></font>";
278 $output.= $GLOBALS["SOBE"]->doc->section('SQL error',$out,0,1);
279 } else {
280 $cPR = $this->getQueryResultCode($mQ,$res,$qGen->table);
281 $output.=$GLOBALS["SOBE"]->doc->section($cPR["header"],$cPR["content"],0,1);
282 }
283 }
284 }
285 return $output;
286 }
287 function getQueryResultCode($mQ,$res,$table) {
288 global $TCA;
289 $output="";
290 $cPR=array();
291 switch($mQ) {
292 case "count":
293 $row = mysql_fetch_row($res);
294 $cPR["header"]='Count';
295 $cPR["content"]="<BR><strong>".$row[0]. "</strong> records selected.";
296 break;
297 case "all":
298 $rowArr=array();
299 while($row=mysql_fetch_assoc($res)) {
300 $rowArr[]=$this->resultRowDisplay($row,$TCA[$table],$table);
301 $lrow=$row;
302 }
303 if (count($rowArr)) {
304 $out.="<table border=0 cellpadding=2 cellspacing=1>".$this->resultRowTitles($lrow,$TCA[$table],$table).implode(chr(10),$rowArr)."</table>";
305 }
306 if (!$out) $out="<em>No rows selected!</em>";
307 $cPR["header"]='Result';
308 $cPR["content"]=$out;
309 break;
310 case "csv":
311 $rowArr=array();
312 $first=1;
313 while($row=mysql_fetch_assoc($res)) {
314 if ($first) {
315 $rowArr[]=$this->csvValues(array_keys($row),",","");
316 $first=0;
317 }
318 $rowArr[]=$this->csvValues($row);
319 }
320 if (count($rowArr)) {
321 $out.='<textarea name="whatever" rows="20" wrap="off"'.$GLOBALS["SOBE"]->doc->formWidthText($this->formW,"","off").'>'.t3lib_div::formatForTextarea(implode(chr(10),$rowArr)).'</textarea>';
322 if (!$this->noDownloadB) {
323 $out.='<BR><input type="submit" name="download_file" value="Click to download file" onClick="document.location=\''.$this->downloadScript.'\';">'; // document.forms[0].target=\'_blank\';
324 }
325 // Downloads file:
326 if (t3lib_div::GPvar("download_file")) {
327 $filename="TYPO3_".$table."_export_".date("dmy-Hi").".csv";
328 $mimeType = "application/octet-stream";
329 Header("Content-Type: ".$mimeType);
330 Header("Content-Disposition: attachment; filename=".$filename);
331 echo implode(chr(13).chr(10),$rowArr);
332 exit;
333 }
334 }
335 if (!$out) $out="<em>No rows selected!</em>";
336 $cPR["header"]='Result';
337 $cPR["content"]=$out;
338 break;
339 case "xml":
340 $className=t3lib_div::makeInstanceClassName("t3lib_xml");
341 $xmlObj = new $className("typo3_export");
342 $xmlObj->includeNonEmptyValues=1;
343 $xmlObj->renderHeader();
344 $first=1;
345 while($row=mysql_fetch_assoc($res)) {
346 if ($first) {
347 $xmlObj->setRecFields($table,implode(",",array_keys($row)));
348 // debug($xmlObj->XML_recFields);
349 $first=0;
350 }
351 $xmlObj->addRecord($table,$row);
352 }
353 $xmlObj->renderFooter();
354 if (mysql_num_rows($res)) {
355 $xmlData=$xmlObj->getResult();
356 $out.='<textarea name="whatever" rows="20" wrap="off"'.$GLOBALS["SOBE"]->doc->formWidthText($this->formW,"","off").'>'.t3lib_div::formatForTextarea($xmlData).'</textarea>';
357 if (!$this->noDownloadB) {
358 $out.='<BR><input type="submit" name="download_file" value="Click to download file" onClick="document.location=\''.$this->downloadScript.'\';">'; // document.forms[0].target=\'_blank\';
359 }
360 // Downloads file:
361 if (t3lib_div::GPvar("download_file")) {
362 $filename="TYPO3_".$table."_export_".date("dmy-Hi").".xml";
363 $mimeType = "application/octet-stream";
364 Header("Content-Type: ".$mimeType);
365 Header("Content-Disposition: attachment; filename=".$filename);
366 echo $xmlData;
367 exit;
368 }
369 }
370 if (!$out) $out="<em>No rows selected!</em>";
371 $cPR["header"]='Result';
372 $cPR["content"]=$out;
373 break;
374 case "explain":
375 default:
376 while($row=mysql_fetch_assoc($res)) {
377 $out.="<BR>".t3lib_div::view_array($row);
378 }
379 $cPR["header"]='Explain SQL query';
380 $cPR["content"]=$out;
381 break;
382 }
383 return $cPR;
384 }
385 function csvValues($row,$delim=",",$quote='"') {
386 return t3lib_div::csvValues($row,$delim,$quote);
387 }
388 function tableWrap($str) {
389 return '<table border=0 cellpadding=10 cellspacing=0 bgcolor="'.$GLOBALS["TBE_TEMPLATE"]->bgColor4.'"><tr><td nowrap><pre>'.$str.'</pre></td></tr></table>';
390 }
391 function search() {
392 global $TCA;
393 $SET = t3lib_div::GPvar("SET");
394 $swords = $SET["sword"];
395 // $GLOBALS["HTTP_POST_VARS"]["SET"]["sword"]
396 $limit=200;
397 $showAlways=0;
398 if ($swords) {
399 reset($TCA);
400 while(list($table)=each($TCA)) {
401 // Get fields list
402 t3lib_div::loadTCA($table);
403 $conf=$TCA[$table];
404
405 reset($conf["columns"]);
406 $list=array();
407 while(list($field,)=each($conf["columns"])) {
408 $list[]=$field;
409 }
410 // Get query
411 $qp = t3lib_BEfunc::searchQuery(array($swords),$list);
412
413 // Count:
414 $query = "SELECT count(*) FROM ".$table." WHERE ".$qp.t3lib_BEfunc::deleteClause($table);
415 $res = mysql(TYPO3_db,$query);
416 echo mysql_error();
417 list($count)=mysql_fetch_row($res);
418 if($count || $showAlways) {
419 // Output header:
420 $out.="<strong>TABLE:</strong> ".$GLOBALS["LANG"]->sL($conf["ctrl"]["title"])."<BR>";
421 $out.="<strong>Results:</strong> ".$count."<BR>";
422
423 // Show to limit
424 if ($count) {
425 $query = "SELECT uid,pid,".$conf["ctrl"]["label"]." FROM ".$table." WHERE ".$qp.t3lib_BEfunc::deleteClause($table)." LIMIT ".$limit;
426 $res = mysql(TYPO3_db,$query);
427 $rowArr=array();
428 while($row=mysql_fetch_assoc($res)) {
429 $rowArr[]=$this->resultRowDisplay($row,$conf,$table);
430 $lrow=$row;
431 }
432 $out.="<table border=0 cellpadding=2 cellspacing=1>".$this->resultRowTitles($lrow,$conf,$table).implode(chr(10),$rowArr)."</table>";
433 }
434 $out.="<HR>";
435 }
436 }
437 }
438 return $out;
439 }
440
441 function resultRowDisplay($row,$conf,$table) {
442 $out='<tr bgcolor="'.$GLOBALS["SOBE"]->doc->bgColor4.'">';
443 reset($row);
444 while(list($fN,$fV)=each($row)) {
445 $TDparams = " nowrap";
446 $fVnew = t3lib_BEfunc::getProcessedValueExtra($table,$fN,$fV);
447 $out.='<td'.$TDparams.'>'.htmlspecialchars($fVnew).'</td>';
448 }
449 $params = '&edit['.$table.']['.$row["uid"].']=edit';
450 $out.='<td nowrap><A HREF="#" onClick="top.launchView(\''.$table.'\','.$row["uid"].',\''.$GLOBALS["BACK_PATH"].'\');return false;"><img src="'.$GLOBALS["BACK_PATH"].'gfx/zoom2.gif" width="12" height="12" border="0" alt=""></a><A HREF="#" onClick="'.t3lib_BEfunc::editOnClick($params,$GLOBALS["BACK_PATH"],t3lib_div::getIndpEnv("REQUEST_URI").t3lib_div::implodeArrayForUrl("SET",$GLOBALS["HTTP_POST_VARS"]["SET"])).'"><img src="'.$GLOBALS["BACK_PATH"].'gfx/edit2.gif" width="11" height="12" border="0" alt=""></a></td>
451 </tr>
452 ';
453 return $out;
454 }
455 function resultRowTitles($row,$conf,$table) {
456 $out='<tr bgcolor="'.$GLOBALS["SOBE"]->doc->bgColor5.'">';
457 reset($row);
458 while(list($fN,$fV)=each($row)) {
459 if (strlen($fV)<50) {$TDparams = " nowrap";} else {$TDparams = "";}
460 $out.='<td'.$TDparams.'><strong>'.$GLOBALS["LANG"]->sL($conf["columns"][$fN]["label"]?$conf["columns"][$fN]["label"]:$fN,1).'</strong></td>';
461 }
462 $out.='<td nowrap></td>
463 </tr>
464 ';
465 return $out;
466 }
467 }
468
469
470 if (defined("TYPO3_MODE") && $TYPO3_CONF_VARS[TYPO3_MODE]["XCLASS"]["t3lib/class.t3lib_fullsearch.php"]) {
471 include_once($TYPO3_CONF_VARS[TYPO3_MODE]["XCLASS"]["t3lib/class.t3lib_fullsearch.php"]);
472 }
473
474 ?>