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 1457 2011-06-25 17:18:50Z Luisehahne $
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
class DseTwo {
18

    
19
	const USE_ALL       = 0;
20
	const USE_BLACKLIST = 1;
21
	const USE_WHITELIST = 2;
22

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

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

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

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

    
313
}
314
?>
(1-1/18)