]> git.mxchange.org Git - ctracker.git/blob - libs/lib_connect.php
Continued:
[ctracker.git] / libs / lib_connect.php
1 <?php
2 /**
3  * Database connection library
4  *
5  * @author              Roland Haeder <webmaster@shipsimu.org>
6  * @version             3.0.0
7  * @copyright   Copyright (c) 2009 - 2017 Cracker Tracker Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.shipsimu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 // Function to aquire a database link
26 function aquireCrackerTrackerDatabaseLink () {
27         // Is the link up?
28         if ((!isCrackerTrackerDatabaseLinkUp()) && (!empty($GLOBALS['ctracker_host'])) && (!empty($GLOBALS['ctracker_dbname'])) && (!empty($GLOBALS['ctracker_user']))) {
29                 // Then connect to the database
30                 $GLOBALS['ctracker_link'] = mysqli_connect($GLOBALS['ctracker_host'], $GLOBALS['ctracker_user'], $GLOBALS['ctracker_password'], $GLOBALS['ctracker_dbname']) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
31
32                 //  Check on connection and config table
33                 if (!isCrackerTrackerDatabaseLinkUp()) {
34                         // Connect didn't work
35                         crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
36                 } elseif (isCrackerTrackerTableCreated('ctracker_config')) {
37                         // Load the config
38                         crackerTrackerLoadConfig();
39                 }
40         } else {
41                 // Init fake config
42                 crackerTrackerInitFakeConfig();
43         }
44 }
45
46 // Inits a fake configurtation
47 function crackerTrackerInitFakeConfig () {
48         // Set the array
49         $GLOBALS['ctracker_config'] = [
50                 'ctracker_alert_user' => 'Y',
51         ];
52 }
53
54 // Checks if the link is up
55 function isCrackerTrackerDatabaseLinkUp () {
56         // Is the instance at least set?
57         if (isset($GLOBALS['ctracker_link'])) {
58                 // Debug message
59                 //* DEBUG: */ error_log('isset='.intval(isset($GLOBALS['ctracker_link'])) . ',is_object=' . intval(is_object($GLOBALS['ctracker_link'])) . ',mysqli_connect_errno=' . mysqli_connect_errno());
60         } else {
61                 // Not set!
62                 //* DEBUG: */ error_log('ctracker_link not set.');
63         }
64
65         return ((isset($GLOBALS['ctracker_link'])) && (is_object($GLOBALS['ctracker_link'])) && (mysqli_connect_errno() == 0));
66 }
67
68 // Database error detected
69 function crackerTrackerDatabaseError (string $file, int $line) {
70         // Should we debug?
71         if (isCrackerTrackerDebug()) {
72                 // Output error
73                 print 'Function    : ' . $file . '<br />' . PHP_EOL;
74                 print 'Line        : ' . $line . '<br />' . PHP_EOL;
75                 if (isset($GLOBALS['ctracker_link']) && $GLOBALS['ctracker_link'] !== false) {
76                         print 'MySQL error : ' . mysqli_error($GLOBALS['ctracker_link']) . '<br />' . PHP_EOL;
77                 } else {
78                         print 'No MySQLi available.<br />' . PHP_EOL;
79                 }
80                 if (isset($GLOBALS['ctracker_last_sql'])) {
81                         print 'Last SQL    : '. $GLOBALS['ctracker_last_sql'] . '<br />' . PHP_EOL;
82                 } else {
83                         print 'No last SQL command available.<br />' . PHP_EOL;
84                 }
85         }
86
87         // Currently only die here
88         crackerTrackerDie();
89 }
90
91 // Closes a maybe open database link
92 function crackerTrackerCloseDatabaseLink () {
93         // The link should be up here
94         if (!isCrackerTrackerDatabaseLinkUp()) {
95                 // Throw exception
96                 throw new BadFunctionCallException('Link is not up.');
97         }
98
99         // Did it work?
100         if (!mysqli_close($GLOBALS['ctracker_link'])) {
101                 // Attempt has failed
102                 crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
103         }
104 }
105
106 // Inserts given array, if IP/check_get combination was not found
107 function crackerTrackerInsertArray (string $table, array $rowData) {
108         // Is it found?
109         if (!isCrackerTrackerEntryFound($rowData)) {
110                 // Reset insert id
111                 $GLOBALS['ctracker_last_insert_id'] = false;
112
113                 // Run it
114                 runCrackerTrackerSql(sprintf("INSERT INTO `%s` (`%s`) VALUES(%s)",
115                         $table,
116                         implode('`,`', array_keys($rowData)),
117                         implode_secure($rowData)
118                 ), __FUNCTION__, __LINE__);
119
120                 // Remember the last insert id
121                 $GLOBALS['ctracker_last_insert_id'] = mysqli_insert_id($GLOBALS['ctracker_link']) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
122         } else {
123                 // Only update the entry
124                 updateCrackerTrackerEntry($rowData);
125         }
126 }
127
128 // Updates a given entry by just counting it up
129 function updateCrackerTrackerEntry (array $rowData, string $countColumn = 'count') {
130         // The link should be up here
131         if (!isCrackerTrackerDatabaseLinkUp()) {
132                 // Throw exception
133                 throw new BadFunctionCallException('Link is not up.');
134         }
135
136         // Run the SQL and check if we have one line
137         runCrackerTrackerSql(sprintf("UPDATE `ctracker_data` SET `%s`=`%s`+1 WHERE (`remote_addr`='%s' AND `proxy_addr`='%s') LIMIT 1",
138                 $countColumn,
139                 $countColumn,
140                 crackerTrackerEscapeString($rowData['remote_addr']),
141                 crackerTrackerEscapeString($rowData['proxy_addr'])
142         ), __FUNCTION__, __LINE__);
143 }
144
145 // Checks if an entry with IP/check_get/domain combination is there
146 function isCrackerTrackerEntryFound (array $rowData) {
147         // The link should be up here
148         if (!isCrackerTrackerDatabaseLinkUp()) {
149                 // Throw exception
150                 throw new BadFunctionCallException('Link is not up.');
151         }
152
153         // Run the SQL and check if we have one line
154         $result = runCrackerTrackerSql(sprintf("SELECT `id` FROM `ctracker_data` WHERE (`remote_addr`='%s' OR `proxy_addr`='%s') AND `check_get` = '%s' AND `server_name`='%s' LIMIT 1'",
155                 crackerTrackerEscapeString($rowData['remote_addr']),
156                 crackerTrackerEscapeString($rowData['proxy_addr']),
157                 crackerTrackerEscapeString($rowData['check_get']),
158                 crackerTrackerEscapeString($rowData['server_name'])
159         ), __FUNCTION__, __LINE__);
160
161         // Check count of rows
162         return (mysqli_num_rows($result) == 1);
163 }
164
165 // Escapes the string
166 function crackerTrackerEscapeString (string $string) {
167         // Is the link up?
168         if (!isCrackerTrackerDatabaseLinkUp()) {
169                 // Then we cant use mysqli_real_escape_string!
170                 $string = htmlentities($string, ENT_QUOTES);
171         } elseif (function_exists('mysqli_real_escape_string')) {
172                 // Use mysqli_real_escape_string()
173                 $string = mysqli_real_escape_string($GLOBALS['ctracker_link'], $string);
174         } else {
175                 // Use fall-back (bad!)
176                 $string = htmlentities($string, ENT_QUOTES);
177         }
178
179         // Return the secured string
180         return $string;
181 }
182
183 // Runs an SQL query and checks for errors
184 function runCrackerTrackerSql (string $sqlString, string $function, int $line) {
185         // Is the link up?
186         if (!isCrackerTrackerDatabaseLinkUp()) {
187                 // Abort here
188                 crackerTrackerDie();
189         }
190
191         // Remember last SQL
192         $GLOBALS['ctracker_last_sql'] = $sqlString;
193
194         // Run the query
195         $GLOBALS['ctracker_last_result'] = mysqli_query($GLOBALS['ctracker_link'], $sqlString) or crackerTrackerDatabaseError($function, $line);
196
197         // And return it
198         return $GLOBALS['ctracker_last_result'];
199 }
200
201 // Checks wether a table was found
202 function isCrackerTrackerTableCreated (string $table) {
203         // Default is not found
204         $found = false;
205
206         // Run the query
207         $result = runCrackerTrackerSql('SHOW TABLES', __FUNCTION__, __LINE__);
208
209         // Is our table there?
210         while (list($tab) = mysqli_fetch_row($result)) {
211                 // Debug message
212                 //* NOISY-DEBUG: */ error_log('tab=' . $tab);
213
214                 // Is the table there?
215                 if ($tab == $table) {
216                         // Okay, found. So abort
217                         $found = true;
218                         break;
219                 }
220         }
221
222         // Free result
223         freeCrackerTrackerResult($result);
224
225         // Return result
226         return $found;
227 }
228
229 // Creates the given table with columns
230 function crackerTrackerCreateTable (string $table, array $columns, array $keys) {
231         // Begin the SQL
232         $sqlString = 'CREATE TABLE IF NOT EXISTS `' . $table . '` (';
233
234         // Add table name as first column
235         $sqlString .= '`' . $table . '` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT, ';
236
237         // Add all columns
238         foreach ($columns as $column=>$type) {
239                 // Add this entry
240                 $sqlString .= '`' . $column . '` ' . $type . ', ';
241         }
242
243         // Add table name as primary key
244         $sqlString .= 'PRIMARY KEY (`' . $table . '`), ';
245
246         // Add keys
247         foreach ($keys as $key => $type) {
248                 // Add this entry
249                 $sqlString .= '' . $type . ' (`' . $key . '`), ';
250         }
251
252         // Finish SQL
253         $sqlString = substr($sqlString, 0, -2) . ') TYPE=InnoDB';
254
255         // And run it
256         runCrackerTrackerSql($sqlString);
257 }
258
259 // Inits a table by inserting
260 function crackerTrackerInitTable (string $table) {
261         // Prepare SQL and run it
262         runCrackerTrackerSql(sprintf("INSERT INTO `%s` (`%s`) VALUES (NULL)'",
263                 $table,
264                 $table
265         ));
266 }
267
268 // Updates the database scheme automatically
269 function crackerTrackerUpdateDatabaseScheme () {
270         // Is a link there?
271         if (!isCrackerTrackerDatabaseLinkUp()) {
272                 // Abort here silently
273                 return;
274         }
275
276         // Is the main config table there?
277         if (!isCrackerTrackerTableCreated('ctracker_config')) {
278                 // Then do it for us
279                 crackerTrackerCreateTable('ctracker_config', [
280                         'ctracker_db_version' => 'BIGINT ( 20 ) UNSIGNED NOT NULL DEFAULT 0',
281                         'ctracker_min_sleep'  => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 10',
282                         'ctracker_max_sleep'  => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 30',
283                         'ctracker_alert_user' => "ENUM('Y','N') NOT NULL DEFAULT 'Y'",
284                         'ctracker_language'   => "CHAR ( 2) NOT NULL DEFAULT 'en'"
285                 ], [
286                 ]);
287
288                 // Init that table
289                 crackerTrackerInitTable('ctracker_config');
290         }
291
292         // Init update array here
293         crackerTrackerInitUpdates();
294
295         // Run any SQL updates recursively
296         while (isset($GLOBALS['ctracker_updates'][getCrackerTrackerConfig('ctracker_db_version')])) {
297                 // Run that updates
298                 runCrackerTrackerUpdates(getCrackerTrackerConfig('ctracker_db_version'));
299
300                 // Update config
301                 runCrackerTrackerSql('UPDATE `ctracker_config` SET `ctracker_db_version`=`ctracker_db_version`+1 WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
302
303                 // And count it up in the config array
304                 $GLOBALS['ctracker_config']['ctracker_db_version']++;
305         }
306 }
307
308 // Load the configuration
309 function crackerTrackerLoadConfig () {
310         // Construct SQL command and run it
311         $result = runCrackerTrackerSql('SELECT * FROM `ctracker_config` WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
312
313         // And get it
314         $GLOBALS['ctracker_config'] = mysqli_fetch_array($result);
315
316         // Free result
317         freeCrackerTrackerResult($result);
318 }
319
320 // Getter for config
321 function getCrackerTrackerConfig (string $entry) {
322         // Is the config entry there?
323         if (!isset($GLOBALS['ctracker_config'][$entry])) {
324                 // Then better die here, else we may have an endless loop
325                 if (isCrackerTrackerDebug()) {
326                         // Nicer message in debug mode
327                         die('Configuration entry ' . $entry . ' missing!');
328                 } else {
329                         // die() on production systems
330                         die();
331                 }
332         }
333
334         // Return it
335         return $GLOBALS['ctracker_config'][$entry];
336 }
337
338 // Did the current IP already generated blocked attempts?
339 function isCrackerTrackerIpSuspicious () {
340         // Skip this silently if we have not config
341         if (!isCrackerTrackerDatabaseLinkUp()) {
342                 // Skip this step silently, all is not suspicious
343                 return false;
344         }
345
346         // Check if an entry is there
347         $result = runCrackerTrackerSql("SELECT COUNT(`id`) AS `cnt` FROM `ctracker_data` USE INDEX (`remote_proxy_last`) WHERE `remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `proxy_addr`='" . getenv('REMOTE_ADDR') . "' LIMIT 1", __FUNCTION__, __LINE__);
348
349         // Get row count
350         list($rows) = mysqli_fetch_row($result);
351
352         // Is there one entry?
353         $found = ($rows > 0);
354
355         // And again?
356         if ($found === true) {
357                 // Yes, one is found, then load it
358                 $result = runCrackerTrackerSql("SELECT SQL_SMALL_RESULT * FROM `ctracker_data` USE INDEX (`remote_proxy_last`) WHERE `remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `proxy_addr`='" . getenv('REMOTE_ADDR') . "' ORDER BY `last_attempt` DESC LIMIT 1", __FUNCTION__, __LINE__);
359
360                 // Cache the entry
361                 $GLOBALS['ctracker_last_suspicious_entry'] = mysqli_fetch_array($result);
362         }
363
364         // Free result
365         freeCrackerTrackerResult($result);
366
367         // Return the result
368         return $found;
369 }
370
371 // Does the current IP have a ticket?
372 function ifCrackerTrackerIpHasTicket () {
373         // We only give one ticket per IP!
374         $result = runCrackerTrackerSql("SELECT * FROM `ctracker_ticket` WHERE `ctracker_ticket_remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `ctracker_ticket_proxy_addr`='" . getenv('REMOTE_ADDR') . "' LIMIT 1", __FUNCTION__, __LINE__);
375
376         // Do we have a ticket?
377         $found = (mysqli_num_rows($result) == 1);
378
379         // And again?
380         if ($found === true) {
381                 // Cache the ticket data
382                 $GLOBALS['ctracker_last_ticket'] = mysqli_fetch_array($result);
383         }
384
385         // Free result
386         freeCrackerTrackerResult($result);
387
388         // Return the result
389         return $found;
390 }
391
392 // Adds a ticket based on given (mostly $_POST) data
393 function addCrackerTrackerTicket (array $data) {
394         // Prepare the array
395         $GLOBALS['ctracker_last_ticket'] = [
396                 'ctracker_ticket_remote_addr' => determineCrackerTrackerRealRemoteAddress(),
397                 'ctracker_ticket_proxy_addr'  => getenv('REMOTE_ADDR'),
398                 'ctracker_ticket_user_agent'  => crackerTrackerUserAgent(),
399                 'ctracker_ticket_name'        => crackerTrackerSecureString($data['name']),
400                 'ctracker_ticket_email'       => crackerTrackerSecureString($data['email']),
401                 'ctracker_ticket_comment'     => crackerTrackerSecureString($data['comment'])
402         ];
403
404         // Insert it
405         crackerTrackerInsertArray('ctracker_ticket', $GLOBALS['ctracker_last_ticket']);
406
407         // Is there an entry?
408         if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
409                 // All fine, so prepare the link between ticket<->data
410                 $data = [
411                         'ctracker_ticket_id' => $GLOBALS['ctracker_last_insert_id'],
412                         'ctracker_data_id'   => $GLOBALS['ctracker_last_suspicious_entry']['id']
413                 ];
414
415                 // And insert it as well
416                 crackerTrackerInsertArray('ctracker_ticket_data', $data);
417
418                 // Add ticket id again
419                 $GLOBALS['ctracker_ticket'] = $data['ctracker_ticket_id'];
420
421                 // Merge all data for emails
422                 $GLOBALS['ctracker_last_ticket'] = array_merge($GLOBALS['ctracker_last_ticket'], $data);
423
424                 // Is this also there?
425                 if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
426                         // All fine, so display "thank you page"
427                         crackerTrackerLoadTemplate('add_ticket_thanks');
428                 } else {
429                         // Did not insert
430                         crackerTrackerDie();
431                 }
432         } else {
433                 // Did not insert
434                 crackerTrackerDie();
435         }
436 }
437
438 // Frees given result instance
439 function freeCrackerTrackerResult (mysqli_result $result) {
440         // Free result
441         $result->free();
442 }