Project

General

Profile

wb-2_10_x / branches / main / framework / DseTwo.php @ 10

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 2 2017-07-02 15:14:29Z Manuela $
9
 * @filesource      $HeadURL: svn://isteam.dynxs.de/wb/2.10.x/branches/main/framework/DseTwo.php $
10
 * @description     Searchengine to browse whoole database for text.
11
 *                  Black- or whitelist is possible
12
 *                  min requirements: PHP 5.3.6, 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
if(!defined('WB_PATH')) {
19
    require_once(dirname(__FILE__).'/globalExceptionHandler.php');
20
    throw new IllegalFileException();
21
}
22
/* -------------------------------------------------------- */
23

    
24
class DseTwo {
25

    
26
    const USE_ALL       = 0;
27
    const USE_BLACKLIST = 1;
28
    const USE_WHITELIST = 2;
29

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

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

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

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

    
325
}