Project

General

Profile

1
<?php
2
/**
3
 * @category        ISTeasy
4
 * @package         DatabaseSearchEngine 1
5
 * @author          Werner von der Decken
6
 * @copyright       2011, ISTeasy-project
7
 * @license         http://www.gnu.org/licenses/gpl.html
8
 * @version         $Id: DseTwo.php 1496 2011-08-11 16:15:31Z DarkViper $
9
 * @filesource		$HeadURL: svn://isteam.dynxs.de/wb-archiv/branches/2.8.x/wb/framework/DseTwo.php $
10
 * @description     Searchengine to browse whoole database for text.
11
 *                  Black- or whitelist is possible
12
 *                  min requirements: PHP 5.2.2, mySQL 5.1
13
 *                  this is a authorisised GPL-lizensed derivate from the original
14
 *                  ISTeasy class DseOne which is available under a cc-by-sa-3.0 license
15
*/
16
/* -------------------------------------------------------- */
17
// Must include code to stop this file being accessed directly
18
require_once('globalExceptionHandler.php');
19
if(!defined('WB_PATH')) { throw new IllegalFileException(); }
20
/* -------------------------------------------------------- */
21

    
22
class DseTwo {
23

    
24
	const USE_ALL       = 0;
25
	const USE_BLACKLIST = 1;
26
	const USE_WHITELIST = 2;
27

    
28
	const RETURN_UNUSED = 0;
29
	const RETURN_USED   = 1;
30
	/**
31
	 *
32
	 * @var object database 
33
	 */
34
	private $_db;
35
	/**
36
	 *
37
	 * @var string prefix of tables to search for
38
	 */
39
	private $_TablePrefix;
40
	/**
41
	 *
42
	 * @var string name of the database
43
	 */
44
	private $_db_name;
45
	/**
46
	 *
47
	 * @var array list of unneeded tables.fields
48
	 */
49
	private $_ControllList;
50
	private $_ControllListTyp;
51
	private $_ControllListTypen = array('All','BlackList','WhiteList');
52

    
53
	private $_Queries;
54
	private $_BasePath = '';
55
	private $_CachePath = '';
56
	private $_TCacheFile = '';
57
	private $_DCachePrefix = '';
58
	private $_bUseCache = true;
59
	/**
60
	 *
61
	 * @param object $database global database object
62
	 */
63
	public function __construct()
64
	{
65
		$this->_ControllList = array();
66
		$this->_TCacheFile = 'Ie'.__CLASS__.'CacheTables';
67
		$this->_DCachePrefix = 'Ie'.__CLASS__.'CacheDir';
68
		$this->_Queries = array();
69
	}
70
	/**
71
	 *
72
	 * @param string $name name of the property
73
	 *        (db_handle, db_name, table_prefix, base_dir, cache_dir, use_cache)
74
	 * @param mixed $value value of the property
75
	 */
76
	public function  __set($name, $value) {
77

    
78
		switch(strtolower($name)):
79
			case 'db_handle':
80
				if($value) { $this->_db = $value; }
81
				break;
82
			case 'db_name':
83
				if($value != '') { $this->_db_name = $value; }
84
				break;
85
			case 'table_prefix':
86
				if($value != '') { $this->_TablePrefix = $value; }
87
				break;
88
			case 'base_dir':
89
				if($value != '') {
90
					$this->_BasePath = rtrim(str_replace('\\', '/', $value) , '/');
91
				}
92
				break;
93
			case 'cache_dir':
94
				$value = rtrim(str_replace('\\', '/', $value) , '/');
95
				if(!is_dir($value)) {
96
					if(!mkdir($value, 0777, true)) {
97
						$this->_CachePath = '';
98
						$this->_bUseCache = false;
99
						break;
100
					}
101
				}
102
				if(is_writable($value)) {
103
					$this->_CachePath = $value;
104
					$this->_bUseCache = true;
105
				}else {
106
					$this->_CachePath = '';
107
					$this->_bUseCache = false;
108
				}
109
				break;
110
			default:
111
				throw new InvalidArgumentException( __CLASS__.'::'.$name );
112
				break;
113
		endswitch;
114
	}
115

    
116
	/**
117
	 * delete all table cache files
118
	 */
119
	public function clearCache()
120
	{
121
		foreach($this->_ControllListTypen as $type) {
122
			$cFile = $this->_CachePath.'/'.$this->_TCacheFile.$type;
123
			if(file_exists($cFile)) { @unlink($cFile); }
124
		}
125
	}
126
	/**
127
	 *
128
	 * @param string $blacklist path/filename of the blacklist
129
	 * @param int $type const USE_NO_LIST / USE_BLACKLIST / USE_WHITELIST
130
	 * @return bool false if no or empty list is available
131
	 */
132
	public function addControllList($sControllList, $type = self::USE_BLACKLIST)
133
	{
134
		$this->_ControllList = array();
135
		$this->_ControllListTyp = $type;
136
		if(is_readable($sControllList)) {
137
			if(($list = file($sControllList, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)) !== false)
138
			{
139
				$list = preg_grep('/^\s*?[^#;]/', $list);
140
				$this->_ControllList = preg_replace('/^\s*?(.*)\s*?$/', $this->_TablePrefix.'$1', $list);
141
				unset($list);
142
			}
143
		}else {
144
			$this->_ControllListTyp = self::USE_ALL;
145
		}
146
		if(($type == self::USE_BLACKLIST) && (sizeof($this->_ControllList) > 0)) {
147
			$this->_ControllListTyp = self::USE_ALL;
148
		}
149
		return (sizeof($this->_ControllList) > 0);
150
	}
151
	/**
152
	 *
153
	 * @param string $sDirToSearch directory to scan (relative to base_dir)
154
	 * @param integer $bRetunMode select matching or unmatching files
155
	 * @return array list of matching files
156
	 */
157
	public function getMatchesFromDir($sDirToSearch, $bRetunMode = self::RETURN_USED)
158
	{
159
		$aResultFileList = array();
160
		$aNewFileList = array();
161
		$sDirToSearch = trim(str_replace('\\', '/', $sDirToSearch) , '/');
162
		$sPathToSearch = $this->_BasePath.'/'.$sDirToSearch;
163
		$sCacheFile = $this->_DCachePrefix.$bRetunMode.urlencode('/'.$sDirToSearch);
164
		$sCacheFile = $this->_CachePath.'/'.$sCacheFile;
165
		if(sizeof($this->_Queries) <= 0) { $this->_getTableQueries(); }
166
		// read fileList from directory
167
		try{
168
			foreach( new DirectoryIterator($sPathToSearch) as $fileinfo ) {
169
			// at first collect all files from target directory
170
				$fileName = $fileinfo->getFilename();
171
				if(($fileinfo->isFile()) &&
172
				   (!$fileinfo->isDot()) &&
173
				   ($fileinfo->getFilename() != 'index.php')) {
174
				   $aNewFileList[] = $fileinfo->getFilename();
175
				}
176
			}
177
		}catch(UnexpectedValueException $e) {}
178
		// make checksum of current directory
179
		$bCacheValid = false;
180
		if($this->_bUseCache) {
181
			$checkSum = crc32(serialize($aNewFileList));
182
			if(is_readable($sCacheFile)){
183
			// read cachefile if available
184
				$aResultFileList = unserialize(file_get_contents($sCacheFile));
185
				if($checkSum == array_shift($aResultFileList)) {
186
				// compare new checksum against checksum from cachefile
187
					$bCacheValid = true;
188
				}
189
			}
190
		}
191
		if(!$bCacheValid) {
192
		// skip this loop if valid cache is available
193
			$aResultFileList = array();
194
			while (list( , $sFilename) = each($aNewFileList)) {
195
				// iterate all tables and search for filename
196
				if( $this->_getMatch($sDirToSearch.'/'.$sFilename) !== false) {
197
					if($bRetunMode == self::RETURN_USED) { $aResultFileList[] = $sFilename; }
198
				}else {
199
					if($bRetunMode == self::RETURN_UNUSED) { $aResultFileList[] = $sFilename; }
200
				}
201
			}
202
			// calculate new checksum
203
			$newCheckSum = crc32(serialize($aResultFileList));
204
			// add checksum to array
205
			array_unshift($aResultFileList,  $newCheckSum);
206
			// try to write serialized array into new cachefile
207
			if(file_put_contents($sCacheFile, serialize($aResultFileList)) === false) {
208
				throw new RuntimeException();
209
			}
210
			// remove checksum again
211
			array_shift($aResultFileList);
212
		}
213
		unset($aNewFileList);
214
		return $aResultFileList;
215
	}
216
	/**
217
	 *
218
	 * @param <type> $sFilename
219
	 * @return bool true if file found in db
220
	 */
221
	private function _getMatch($sFilename)
222
	{
223
		$result = 0;
224
		$sFilename = str_replace('_', '\_', $sFilename);
225
		$sSearch = '%'.str_replace('/', '_', $sFilename).'%';
226
		while (list( , $sQuery) = each($this->_Queries)) {
227
			$sql = sprintf($sQuery, $sSearch);
228
			if( ($res = mysql_query($sql, $this->_db)) ) {
229
				if( ($result = intval(mysql_fetch_array($res))) > 0 )  { break; }
230
			}
231
		}
232
		return ($result != 0);
233
	}
234
	/**
235
	 *
236
	 */
237
	private function _getTableQueries()
238
	{
239
		if($this->_bUseCache) {
240
		// try to read queries from cace
241
			$sCacheFile = $this->_CachePath.'/'.$this->_TCacheFile.$this->_ControllListTypen[$this->_ControllListTyp];
242
			try {
243
				if(is_readable($sCacheFile)) {
244
					$this->_Queries = unserialize(file_get_contents($sCacheFile));
245
				}
246
			}catch(Exception $e) {
247
				$this->_Queries = array();
248
			}
249
		}
250
		if(sizeof($this->_Queries) > 0) { return; } // queries alreade loaded from cache
251
		$TP = str_replace('_','\_', $this->_TablePrefix);
252
		$sql  = 'SELECT TABLE_NAME `table`, COLUMN_NAME `column` ';
253
		$sql .= 'FROM INFORMATION_SCHEMA.COLUMNS ';
254
		$sql .= 'WHERE `table_schema` = \''.$this->_db_name.'\' AND ';
255
		$sql .=        '`table_name` LIKE \''.$TP.'%\' AND ';
256
		$sql .=        '(`data_type` LIKE \'%text\' OR ';
257
		$sql .=           '(`data_type` = \'varchar\' AND `character_maximum_length` > 20)';
258
		$sql .=        ')' ;
259
		$sql .= 'ORDER BY `table`, `column`';
260
		if(($res = mysql_query($sql, $this->_db))) {
261
			$lastTable = '';
262
			$aOrStatements = array();
263
			$sPrefix = '';
264
			while($rec = mysql_fetch_assoc($res))
265
			{ // loop through all found tables/fields
266
				$sTableColumn = $rec['table'].'.'.$rec['column'];
267
				switch($this->_ControllListTyp):
268
				// test against controll list
269
					case self::USE_BLACKLIST:
270
						$needRecord = true;
271
						if(in_array($rec['table'], $this->_ControllList) ||
272
						   in_array($sTableColumn, $this->_ControllList))
273
						{
274
							$needRecord = false;
275
						}
276
						break;
277
					case self::USE_WHITELIST:
278
						$needRecord = false;
279
						if(in_array($rec['table'], $this->_ControllList) ||
280
						   in_array($sTableColumn, $this->_ControllList))
281
						{
282
							$needRecord = true;
283
						}
284
						break;
285
					default: // self::USE_ALL
286
						$needRecord = true;
287
						break;
288
				endswitch;
289
				if($needRecord) {
290
					if($lastTable != $rec['table']) {
291
						if(sizeof($aOrStatements)!= 0){
292
						// close previous table
293
							$this->_Queries[] = $sPrefix.implode(') OR (', $aOrStatements).')';
294
						}
295
					// start a new table
296
						$sPrefix = 'SELECT COUNT(*) `count` FROM `'.$rec['table'].'` WHERE( ';
297
						$aOrStatements = array();
298
						$lastTable = $rec['table'];
299
					}
300
					// add table.column to query
301
					$aOrStatements[] = '`'.$rec['table'].'`.`'.$rec['column'].'` LIKE \'%1$s\'';
302
				}
303
			}
304
			if(sizeof($aOrStatements)!= 0){
305
			// close last table
306
				$this->_Queries[] = $sPrefix.implode(') OR (', $aOrStatements).')';
307
			}
308
			mysql_free_result($res);
309
		}
310
		if($this->_bUseCache) {
311
		// try to write queries into the cache
312
			if(file_put_contents($sCacheFile, serialize($this->_Queries)) === false) {
313
				throw new RuntimeException('unable to write file ['.$sCacheFile.']');
314
			}
315
		}
316
	}
317

    
318
}
319
?>
(1-1/19)