1<?php 2/* 3 ********************************************************************* 4 * LogAnalyzer - http://loganalyzer.adiscon.com 5 * ----------------------------------------------------------------- * 6 * Some constants * 7 * * 8 * LogStreamDB provides access to the data in database. In the most 9 * cases this will be plain text files. If we need access to e.g. 10 * zipped files, this will be handled by a separate driver. 11 * 12 * \version 2.0.0 Init Version 13 * * 14 * All directives are explained within this file * 15 * 16 * Copyright (C) 2008-2010 Adiscon GmbH. 17 * 18 * This file is part of LogAnalyzer. 19 * 20 * LogAnalyzer is free software: you can redistribute it and/or modify 21 * it under the terms of the GNU General Public License as published by 22 * the Free Software Foundation, either version 3 of the License, or 23 * (at your option) any later version. 24 * 25 * LogAnalyzer is distributed in the hope that it will be useful, 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * GNU General Public License for more details. 29 * 30 * You should have received a copy of the GNU General Public License 31 * along with LogAnalyzer. If not, see <http://www.gnu.org/licenses/>. 32 * 33 * A copy of the GPL can be found in the file "COPYING" in this 34 * distribution. 35 ********************************************************************* 36*/ 37 38// --- Avoid directly accessing this file! 39if ( !defined('IN_PHPLOGCON') ) 40{ 41 die('Hacking attempt'); 42 exit; 43} 44// --- 45 46// --- Required Includes! 47require_once($gl_root_path . 'include/constants_errors.php'); 48// --- 49 50class LogStreamDB extends LogStream { 51 private $_dbhandle = null; 52 53 // Helper to store the database records 54 private $bufferedRecords = null; 55 private $_currentRecordStart = 0; 56 private $_currentRecordNum = 0; 57 private $_totalRecordCount = -1; 58 private $_previousPageUID = -1; 59 private $_lastPageUID = -1; 60 private $_firstPageUID = -1; 61 private $_currentPageNumber = -1; 62 63 private $_SQLwhereClause = ""; 64 private $_myDBQuery = null; 65 66 // Constructor 67 public function __construct ($streamConfigObj) { 68 $this->_logStreamConfigObj = $streamConfigObj; 69 70 if ( $this->_logStreamConfigObj->DBType == DB_MYSQL ) 71 { 72 // Probe if a function exists! 73 if ( !function_exists("mysqli_connect") ) 74 DieWithFriendlyErrorMsg("Error, MYSQL Extensions are not enabled! Function 'mysqli_connect' does not exist."); 75 } 76 } 77 public function LogStreamDB($streamConfigObj) { 78 self::__construct($streamConfigObj); 79 } 80 81 /** 82 * Open and verifies the database conncetion 83 * 84 * @param arrProperties array in: Properties wish list. 85 * @return integer Error stat 86 */ 87 public function Open($arrProperties) 88 { 89 global $dbmapping; 90 91 // Initialise Basic stuff within the Classs 92 $this->RunBasicInits(); 93 94 // Verify database connection (This also opens the database!) 95 $res = $this->Verify(); 96 if ( $res != SUCCESS ) 97 return $res; 98 99 // Copy the Property Array 100 $this->_arrProperties = $arrProperties; 101 102 // Check if DB Mapping exists 103 if ( !isset($dbmapping[ $this->_logStreamConfigObj->DBTableType ]) ) 104 return ERROR_DB_INVALIDDBMAPPING; 105 106 // Create SQL Where Clause first! 107 $res = $this->CreateSQLWhereClause(); 108 if ( $res != SUCCESS ) 109 return $res; 110 111 // Success, this means we init the Pagenumber to ONE! 112 // $this->_currentPageNumber = 1; 113 114 // reached this point means success! 115 return SUCCESS; 116 } 117 118 /* 119 * Helper function to clear the current querystring! 120 */ 121 public function ResetFilters() 122 { 123 // Clear _SQLwhereClause variable! 124 $this->_SQLwhereClause = ""; 125 } 126 127 /** 128 * Close the database connection. 129 * 130 * @return integer Error state 131 */ 132 public function Close() 133 { 134 if ($this->_dbhandle) 135 mysqli_close($this->_dbhandle); 136 $this->_dbhandle = null; 137 return SUCCESS; 138 } 139 140 /** 141 * Verify if the database connection exists! 142 * 143 * @return integer Error state 144 */ 145 public function Verify() { 146 // Try to connect to the database 147 if ( $this->_dbhandle == null ) 148 { 149 // Forces to open a new link in all cases! 150 $this->_dbhandle = @mysqli_connect($this->_logStreamConfigObj->DBServer,$this->_logStreamConfigObj->DBUser,$this->_logStreamConfigObj->DBPassword); 151 if (!$this->_dbhandle) 152 { 153 if ( isset($php_errormsg) ) 154 { 155 global $extraErrorDescription; 156 $extraErrorDescription = $php_errormsg; 157 } 158 159 // Return error code 160 return ERROR_DB_CONNECTFAILED; 161 } 162 } 163 164 // Select the database now! 165 $bRet = @mysqli_select_db($this->_dbhandle, $this->_logStreamConfigObj->DBName); 166 if(!$bRet) 167 { 168 if ( isset($php_errormsg) ) 169 { 170 global $extraErrorDescription; 171 $extraErrorDescription = $php_errormsg; 172 } 173 174 // Return error code 175 return ERROR_DB_CANNOTSELECTDB; 176 } 177 178 // Check if the table exists! 179 $numTables = @mysqli_num_rows( mysqli_query($this->_dbhandle, "SHOW TABLES LIKE '%" . $this->_logStreamConfigObj->DBTableName . "%'")); 180 if( $numTables <= 0 ) 181 return ERROR_DB_TABLENOTFOUND; 182 183 // reached this point means success ;)! 184 return SUCCESS; 185 } 186 187 188 /* 189 * Implementation of VerifyFields: Checks if fields exist in table 190 */ 191 public function VerifyFields( $arrProperitesIn ) 192 { 193 global $dbmapping, $fields; 194 195 // Get List of Indexes as Array 196 $arrFieldKeys = $this->GetFieldsAsArray(); 197 $szTableType = $this->_logStreamConfigObj->DBTableType; 198 199 // Loop through all fields to see which one is missing! 200 foreach ( $arrProperitesIn as $myproperty ) 201 { 202// echo $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "<br>"; 203 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) && in_array($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], $arrFieldKeys) ) 204 { 205 OutputDebugMessage("LogStreamDB|VerifyFields: Found Field for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "'", DEBUG_ULTRADEBUG); 206 continue; 207 } 208 else 209 { 210 // Index is missing for this field! 211 OutputDebugMessage("LogStreamDB|VerifyFields: Missing Field for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "'", DEBUG_WARN); 212 return ERROR_DB_DBFIELDNOTFOUND; 213 } 214 } 215 216 // Successfull 217 return SUCCESS; 218 } 219 220 221 /* 222 * Implementation of VerifyIndexes: Checks if indexes exist for desired fields 223 */ 224 public function VerifyIndexes( $arrProperitesIn ) 225 { 226 global $dbmapping, $fields; 227 228 // Get List of Indexes as Array 229 $arrIndexKeys = $this->GetIndexesAsArray(); 230 $szTableType = $this->_logStreamConfigObj->DBTableType; 231 232 // Loop through all fields to see which one is missing! 233 foreach ( $arrProperitesIn as $myproperty ) 234 { 235// echo $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "<br>"; 236 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) && in_array($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], $arrIndexKeys) ) 237 { 238 OutputDebugMessage("LogStreamDB|VerifyIndexes: Found INDEX for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "'", DEBUG_ULTRADEBUG); 239 continue; 240 } 241 else 242 { 243 // Index is missing for this field! 244 OutputDebugMessage("LogStreamDB|VerifyIndexes: Missing INDEX for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "'", DEBUG_WARN); 245 return ERROR_DB_INDEXESMISSING; 246 } 247 } 248 249 // Successfull 250 return SUCCESS; 251 } 252 253 254 /* 255 * Implementation of VerifyChecksumTrigger: Checks if checksum trigger exists 256 */ 257 public function VerifyChecksumTrigger( $myTriggerProperty ) 258 { 259 global $dbmapping, $fields; 260 261 // Get List of Triggers as Array 262 $arrIndexTriggers = $this->GetTriggersAsArray(); 263 264 $szTableType = $this->_logStreamConfigObj->DBTableType; 265 $szDBName = $this->_logStreamConfigObj->DBName; 266 $szTableName = $this->_logStreamConfigObj->DBTableName; 267 $szDBTriggerField = $dbmapping[$szTableType]['DBMAPPINGS'][$myTriggerProperty]; 268 269 // Create Triggername | lowercase! 270 $szTriggerName = strtolower( $szDBName . "_" . $szTableName . "_" . $szDBTriggerField ); 271 272 // Try to find logstream trigger 273 if ( count($arrIndexTriggers) > 0 ) 274 { 275 if ( in_array($szTriggerName, $arrIndexTriggers) ) 276 return SUCCESS; 277 else 278 { 279 // Index is missing for this field! 280 OutputDebugMessage("LogStreamDB|VerifyChecksumTrigger: Missing TRIGGER '" . $szTriggerName . "' for Table '" . $szTableName . "'", DEBUG_WARN); 281 return ERROR_DB_TRIGGERMISSING; 282 } 283 } 284 else 285 { 286 // Index is missing for this field! 287 OutputDebugMessage("LogStreamDB|VerifyChecksumTrigger: No TRIGGERS found in your database", DEBUG_WARN); 288 return ERROR_DB_TRIGGERMISSING; 289 } 290 } 291 292 293 /* 294 * Implementation of CreateMissingIndexes: Checks if indexes exist for desired fields 295 */ 296 public function CreateMissingIndexes( $arrProperitesIn ) 297 { 298 global $dbmapping, $fields, $querycount; 299 300 // Get List of Indexes as Array 301 $arrIndexKeys = $this->GetIndexesAsArray(); 302 $szTableType = $this->_logStreamConfigObj->DBTableType; 303 304 // Loop through all fields to see which one is missing! 305 foreach ( $arrProperitesIn as $myproperty ) 306 { 307 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) && in_array($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], $arrIndexKeys) ) 308 continue; 309 else 310 { 311 // Update Table schema now! 312 $szSql = "ALTER TABLE " . $this->_logStreamConfigObj->DBTableName . " ADD INDEX ( " . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . " )"; 313 314 // Index is missing for this field! 315 OutputDebugMessage("LogStreamDB|CreateMissingIndexes: Createing missing INDEX for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "' - " . $szSql, DEBUG_INFO); 316 317 // Add missing INDEX now! 318 $myQuery = mysqli_query($this->_dbhandle, $szSql); 319 if (!$myQuery) 320 { 321 // Return failure! 322 $this->PrintDebugError("Dynamically Adding INDEX for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "' failed with Statement: '" . $szSql . "'"); 323 return ERROR_DB_INDEXFAILED; 324 } 325 } 326 } 327 328 // Successfull 329 return SUCCESS; 330 } 331 332 333 /* 334 * Implementation of CreateMissingFields: Checks if indexes exist for desired fields 335 */ 336 public function CreateMissingFields( $arrProperitesIn ) 337 { 338 global $dbmapping, $fields, $querycount; 339 340 // Get List of Indexes as Array 341 $arrFieldKeys = $this->GetFieldsAsArray(); 342 $szTableType = $this->_logStreamConfigObj->DBTableType; 343 344 // Loop through all fields to see which one is missing! 345 foreach ( $arrProperitesIn as $myproperty ) 346 { 347 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) && in_array($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], $arrFieldKeys) ) 348 continue; 349 else 350 { 351 if ( $this->HandleMissingField( $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], $arrProperitesIn ) == SUCCESS ) 352 { 353 // Index is missing for this field! 354 OutputDebugMessage("LogStreamDB|CreateMissingFields: Createing missing FIELD for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty], DEBUG_INFO); 355 } 356 else 357 { 358 // Return failure! 359 $this->PrintDebugError("Dynamically Adding FIELD for '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "' failed!"); 360 return ERROR_DB_ADDDBFIELDFAILED; 361 } 362 } 363 } 364 365 // Successfull 366 return SUCCESS; 367 } 368 369 370 /* 371 * Implementation of GetCreateMissingTriggerSQL: Creates SQL needed to create a TRIGGER 372 */ 373 public function GetCreateMissingTriggerSQL( $myDBTriggerField, $myDBTriggerCheckSumField ) 374 { 375 global $dbmapping, $fields, $querycount; 376 377 // Get List of Triggers as Array 378 $szDBName = $this->_logStreamConfigObj->DBName; 379 $szTableName = $this->_logStreamConfigObj->DBTableName; 380 381 // Create Triggername 382 $szTriggerName = $szDBName . "_" . $szTableName . "_" . $myDBTriggerField; 383 384 // Create TRIGGER SQL! 385 $szSql = "CREATE TRIGGER " . $szTriggerName . " BEFORE INSERT ON `" . $szTableName . "` 386 FOR EACH ROW 387 BEGIN 388 SET NEW." . $myDBTriggerCheckSumField . " = crc32(NEW." . $myDBTriggerField . "); 389 END 390 ;"; 391 392 return $szSql; 393 } 394 395 396 /* 397 * Implementation of CreateMissingTrigger: Creates missing triggers ! 398 */ 399 public function CreateMissingTrigger( $myTriggerProperty, $myCheckSumProperty ) 400 { 401 global $dbmapping, $fields, $querycount; 402 403 // Get List of Triggers as Array 404 $szTableName = $this->_logStreamConfigObj->DBTableName; 405 $szTableType = $this->_logStreamConfigObj->DBTableType; 406 $szDBTriggerField = $dbmapping[$szTableType]['DBMAPPINGS'][$myTriggerProperty]; 407 $szDBTriggerCheckSumField = $dbmapping[$szTableType]['DBMAPPINGS'][$myCheckSumProperty]; 408 409 // Get SQL Code to create the trigger! 410 $szSql = $this->GetCreateMissingTriggerSQL( $szDBTriggerField, $szDBTriggerCheckSumField ); 411 412 // Index is missing for this field! 413 OutputDebugMessage("LogStreamDB|CreateMissingTrigger: Creating missing TRIGGER for '" . $szTableName . "' - $szDBTriggerCheckSumField = crc32(NEW.$szDBTriggerField)" . $szSql, DEBUG_INFO); 414 415 // Add missing INDEX now! 416 $myQuery = mysqli_query($this->_dbhandle, $szSql); 417 if (!$myQuery) 418 { 419 // Return failure! 420 $this->PrintDebugError("Dynamically Adding TRIGGER for '" . $szTableName . "' failed!<br/><br/>If you want to manually add the TRIGGER, use the following SQL Command:<br/> " . str_replace("\n", "<br/>", $szSql) . "<br/>"); 421 422 return ERROR_DB_TRIGGERFAILED; 423 } 424 425 // Successfull 426 return SUCCESS; 427 } 428 429 430 /* 431 * Implementation of ChangeChecksumFieldUnsigned: Changes the Checkusm field to unsigned! 432 */ 433 public function ChangeChecksumFieldUnsigned() 434 { 435 global $dbmapping, $fields, $querycount; 436 437 // Get variables 438 $szTableType = $this->_logStreamConfigObj->DBTableType; 439 440 // Change Checksumfield to use UNSIGNED! 441 $szUpdateSql = "ALTER TABLE `" . $this->_logStreamConfigObj->DBTableName . "` CHANGE `" . 442 $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . "` `" . 443 $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . "` INT(11) UNSIGNED NOT NULL DEFAULT '0'"; 444 445 // Update Table schema now! 446 $myQuery = mysqli_query($this->_dbhandle, $szUpdateSql); 447 if (!$myQuery) 448 { 449 // Return failure! 450 $this->PrintDebugError("ER_BAD_FIELD_ERROR - Failed to Change field '" . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . "' from signed to unsigned with sql statement: '" . $szUpdateSql . "'"); 451 return ERROR_DB_CHECKSUMCHANGEFAILED; 452 } 453 454 // return results 455 return SUCCESS; 456 } 457 458 459 /* 460 * Implementation of VerifyChecksumField: Verifies if the checkusm field is signed or unsigned! 461 */ 462 public function VerifyChecksumField() 463 { 464 global $dbmapping, $fields, $querycount; 465 466 // Get variables 467 $szTableType = $this->_logStreamConfigObj->DBTableType; 468 469 // Create SQL and Get INDEXES for table! 470 $szSql = "SHOW COLUMNS FROM `" . $this->_logStreamConfigObj->DBTableName . "` WHERE Field = '" . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . "'"; 471 $myQuery = mysqli_query($this->_dbhandle, $szSql); 472 if ($myQuery) 473 { 474 // Get result! 475 $myRow = mysqli_fetch_array($myQuery, MYSQLI_ASSOC); 476 if (strpos( strtolower($myRow['Type']), "unsigned") === false ) 477 { 478 // return error code! 479 return ERROR_DB_CHECKSUMERROR; 480 } 481 482 // Free query now 483 mysqli_free_result ($myQuery); 484 485 // Increment for the Footer Stats 486 $querycount++; 487 } 488 489 // return results 490 return SUCCESS; 491 } 492 493 494 /** 495 * Read the data from a specific uID which means in this 496 * case beginning with from the Database ID 497 * 498 * @param uID integer in/out: unique id of the data row 499 * @param arrProperitesOut array out: array filled with properties 500 * @return integer Error state 501 * @see ReadNext() 502 */ 503 public function Read($uID, &$arrProperitesOut) 504 { 505 // Seek the first uID! 506 if ( $this->Sseek($uID, EnumSeek::UID, 0) == SUCCESS) 507 { 508 // Read the next record! 509 $ret = $this->ReadNext($uID, $arrProperitesOut); 510 } 511 else 512 $ret = ERROR_NOMORERECORDS; 513 514 // return result! 515 return $ret; 516 } 517 518 /** 519 * Read the next line from the file depending on the current 520 * read direction. 521 * 522 * Hint: If the current stream becomes unavailable an error 523 * stated is retuned. A typical case is if a log rotation 524 * changed the original data source. 525 * 526 * @param uID integer out: uID is the offset of data row 527 * @param arrProperitesOut array out: properties 528 * @return integer Error state 529 * @see ReadNext 530 */ 531 public function ReadNext(&$uID, &$arrProperitesOut, $bParseMessage = true) 532 { 533 // Helpers needed for DB Mapping 534 global $content, $gl_starttime; 535 global $dbmapping, $fields; 536 $szTableType = $this->_logStreamConfigObj->DBTableType; 537 538 // define $ret 539 $ret = SUCCESS; 540 541 do 542 { 543 // No buffer? then read from DB! 544 if ( $this->bufferedRecords == null ) 545 $ret = $this->ReadNextRecordsFromDB($uID); 546 else 547 { 548 if ( !isset($this->bufferedRecords[$this->_currentRecordNum] ) ) 549 { 550 // We need to load new records, so clear the old ones first! 551 $this->ResetBufferedRecords(); 552 553 // Set new Record start, will be used in the SQL Statement! 554 $this->_currentRecordStart = $this->_currentRecordNum; // + 1; 555 556 // Now read new ones 557 $ret = $this->ReadNextRecordsFromDB($uID); 558 559 // Check if we found more records 560 if ( !isset($this->bufferedRecords[$this->_currentRecordNum] ) ) 561 $ret = ERROR_NOMORERECORDS; 562 } 563 } 564 565 if ( $ret == SUCCESS && $this->_arrProperties != null ) 566 { 567 // Init and set variables 568 foreach ( $this->_arrProperties as $property ) 569 { 570 // Check if mapping exists 571 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$property]) ) 572 { 573 // Copy property if available! 574 $dbfieldname = $dbmapping[$szTableType]['DBMAPPINGS'][$property]; 575 if ( isset($this->bufferedRecords[$this->_currentRecordNum][$dbfieldname]) ) 576 { 577 if ( isset($fields[$property]['FieldType']) && $fields[$property]['FieldType'] == FILTER_TYPE_DATE ) // Handle as date! 578 $arrProperitesOut[$property] = GetEventTime( $this->bufferedRecords[$this->_currentRecordNum][$dbfieldname] ); 579 else 580 $arrProperitesOut[$property] = $this->bufferedRecords[$this->_currentRecordNum][$dbfieldname]; 581 } 582 else 583 $arrProperitesOut[$property] = ''; 584 } 585 else 586 $arrProperitesOut[$property] = ''; 587 } 588 589 // Run optional Message Parsers now 590 if ( isset($arrProperitesOut[SYSLOG_MESSAGE]) ) 591 { 592 $retParser = $this->_logStreamConfigObj->ProcessMsgParsers($arrProperitesOut[SYSLOG_MESSAGE], $arrProperitesOut); 593 594 // Check if we have to skip the message! 595 if ( $retParser == ERROR_MSG_SKIPMESSAGE ) 596 $ret = $retParser; 597 } 598 599 // Set uID to the PropertiesOut! //DEBUG -> $this->_currentRecordNum; 600 $uID = $arrProperitesOut[SYSLOG_UID] = $this->bufferedRecords[$this->_currentRecordNum][$dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID]]; 601 602 // Increment $_currentRecordNum 603 $this->_currentRecordNum++; 604 } 605 606 // Check how long we are running. If only two seconds of execution time are left, we abort further reading! 607 $scriptruntime = intval(microtime_float() - $gl_starttime); 608 if ( $content['MaxExecutionTime'] > 0 && $scriptruntime > ($content['MaxExecutionTime']-2) ) 609 { 610 // This may display a warning message, so the user knows we stopped reading records because of the script timeout. 611 $content['logstream_warning'] = "false"; 612 $content['logstream_warning_details'] = $content['LN_WARNING_LOGSTREAMDISK_TIMEOUT']; 613 $content['logstream_warning_code'] = ERROR_FILE_NOMORETIME; 614 615 // Return error code 616 return ERROR_FILE_NOMORETIME; 617 } 618 619 // This additional filter check will take care on dynamic fields from the message parser! 620 } while ( $this->ApplyFilters($ret, $arrProperitesOut) != SUCCESS && $ret == SUCCESS ); 621 622 // reached here means return result! 623 return $ret; 624 } 625 626 /** 627 * Implementation of Seek 628 */ 629 public function Sseek(&$uID, $mode, $numrecs) 630 { 631 // predefine return value 632 $ret = SUCCESS; 633 634 switch ($mode) 635 { 636 case EnumSeek::UID: 637// if ( $uID == UID_UNKNOWN ) // set uID to first ID! 638 { 639 // No buffer? then read from DB! 640 if ( $this->bufferedRecords == null ) 641 $ret = $this->ReadNextRecordsFromDB($uID); 642 643 if ( $ret == SUCCESS ) 644 { 645 $this->_currentRecordNum = 0; 646 $uID = $this->bufferedRecords[ $this->_currentRecordNum ]; 647 } 648 } 649 break; 650 } 651 652 // Return result! 653 return $ret; 654 } 655 656 /** 657 * GetMessageCount will return the count of Message. 658 * If this count is not available, the function will 659 * return the default -1 660 */ 661 public function GetMessageCount() 662 { 663 return $this->_totalRecordCount; 664 } 665 666 /** 667 * This function returns the first UID for previous PAGE, if availbale! 668 * Otherwise will return -1! 669 */ 670 public function GetPreviousPageUID() 671 { 672 return $this->_previousPageUID; 673 } 674 675 /** 676 * This function returns the FIRST UID for the FIRST PAGE! 677 * Will be done by a seperated SQL Statement. 678 */ 679 public function GetFirstPageUID() 680 { 681 global $querycount, $dbmapping; 682 $szTableType = $this->_logStreamConfigObj->DBTableType; 683 684 // Only perform query if row counting is enabled! 685 if ( strlen($this->_SQLwhereClause) > 0 && !$this->_logStreamConfigObj->DBEnableRowCounting ) 686 return $this->_firstPageUID; 687 688 $szSql = "SELECT MAX(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . ") FROM `" . $this->_logStreamConfigObj->DBTableName . "` " . $this->_SQLwhereClause; 689 $myQuery = mysqli_query($this->_dbhandle, $szSql); 690 if ($myQuery) 691 { 692 // obtain first and only row 693 $myRow = mysqli_fetch_row($myQuery); 694 $this->_firstPageUID = $myRow[0]; 695 696 // Free query now 697 mysqli_free_result ($myQuery); 698 699 // Increment for the Footer Stats 700 $querycount++; 701 } 702 703 // Return result! 704 return $this->_firstPageUID; 705 } 706 707 /** 708 * This function returns the first UID for the last PAGE! 709 * Will be done by a seperated SQL Statement. 710 */ 711 public function GetLastPageUID() 712 { 713 global $querycount, $dbmapping; 714 $szTableType = $this->_logStreamConfigObj->DBTableType; 715 716 // Only perform query if row counting is enabled! 717 if ( strlen($this->_SQLwhereClause) > 0 && !$this->_logStreamConfigObj->DBEnableRowCounting ) 718 return $this->_lastPageUID; 719 720 $szSql = "SELECT MIN(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . ") FROM `" . $this->_logStreamConfigObj->DBTableName . "` " . $this->_SQLwhereClause; 721 $myQuery = mysqli_query($this->_dbhandle, $szSql); 722 if ($myQuery) 723 { 724 // obtain first and only row 725 $myRow = mysqli_fetch_row($myQuery); 726 $this->_lastPageUID = $myRow[0]; 727 728 // Free query now 729 mysqli_free_result ($myQuery); 730 731 // Increment for the Footer Stats 732 $querycount++; 733 } 734 735 // Return result! 736 return $this->_lastPageUID; 737 } 738 739 /** 740 * This function returns the current Page number, if availbale! 741 * Otherwise will return 0! We also assume that this function is 742 * only called once DB is open! 743 */ 744 public function GetCurrentPageNumber() 745 { 746 return $this->_currentPageNumber; 747 } 748 749 /* 750 * Implementation of IsPropertySortable 751 * 752 * For now, sorting is only possible for the UID Property! 753 */ 754 public function IsPropertySortable($myProperty) 755 { 756 global $fields; 757 758 // TODO: HARDCODED | FOR NOW only FALSE! 759 return false; 760 761 if ( isset($fields[$myProperty]) && $myProperty == SYSLOG_UID ) 762 return true; 763 else 764 return false; 765 } 766 767 /** 768 * Implementation of GetLogStreamStats 769 * 770 * Returns an Array og logstream statsdata 771 * Count of Data Items 772 * Total Filesize 773 */ 774 public function GetLogStreamStats() 775 { 776 global $querycount, $dbmapping; 777 $szTableType = $this->_logStreamConfigObj->DBTableType; 778 779 // Perform if Connection is true! 780 if ( $this->_dbhandle != null ) 781 { 782 // Obtain Stats data for this table! 783 $szSql = "SHOW TABLE STATUS FROM `" . $this->_logStreamConfigObj->DBName . "`"; 784 $myQuery = mysqli_query($this->_dbhandle, $szSql); 785 if ($myQuery) 786 { 787 // Loop through results 788 while ($myRow = mysqli_fetch_array($myQuery, MYSQLI_ASSOC)) 789 { 790 // Set tablename! 791 $tableName = $myRow['Name']; 792 $myStats = null; 793 $myStats[] = array( 'StatsDisplayName' => 'Table name', 'StatsValue' => $tableName ); 794 795 // copy usefull statsdata 796 if ( isset($myRow['Engine']) ) 797 $myStats[] = array( 'StatsDisplayName' => 'Table engine', 'StatsValue' => $myRow['Engine'] ); 798 if ( isset($myRow['Rows']) ) 799 $myStats[] = array( 'StatsDisplayName' => 'Rowcount', 'StatsValue' => $myRow['Rows'] ); 800 801 if ( isset($myRow['Data_length']) ) 802 $myStats[] = array( 'StatsDisplayName' => 'Table filesize (bytes)', 'StatsValue' => $myRow['Data_length'] ); 803 if ( isset($myRow['Collation']) ) 804 $myStats[] = array( 'StatsDisplayName' => 'Collation', 'StatsValue' => $myRow['Collation'] ); 805 if ( isset($myRow['Comment']) ) 806 $myStats[] = array( 'StatsDisplayName' => 'Comment', 'StatsValue' => $myRow['Comment'] ); 807 808 $stats[]['STATSDATA'] = $myStats; 809 } 810 811 // Free query now 812 mysqli_free_result ($myQuery); 813 814 // Increment for the Footer Stats 815 $querycount++; 816 } 817 818 // return results! 819 return $stats; 820 } 821 else 822 return null; 823 } 824 825 /** 826 * Implementation of GetLogStreamTotalRowCount 827 * 828 * Returns the total amount of rows in the main datatable 829 */ 830 public function GetLogStreamTotalRowCount() 831 { 832 global $querycount, $dbmapping; 833 $szTableType = $this->_logStreamConfigObj->DBTableType; 834 835 // Set default rowcount 836 $rowcount = null; 837 838 // Perform if Connection is true! 839 if ( $this->_dbhandle != null ) 840 { 841 // SHOW TABLE STATUS FROM 842 $szSql = "SELECT count(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . ") as Counter FROM `" . $this->_logStreamConfigObj->DBTableName . "`"; 843 $myQuery = mysqli_query($this->_dbhandle, $szSql); 844 if ($myQuery) 845 { 846 // Obtain RowCount! 847 $myRow = mysqli_fetch_row($myQuery); 848 $rowcount = $myRow[0]; 849 850 // Free query now 851 mysqli_free_result ($myQuery); 852 853 // Increment for the Footer Stats 854 $querycount++; 855 } 856 } 857 858 //return result 859 return $rowcount; 860 } 861 862 /** 863 * Implementation of the CleanupLogdataByDate function! Returns affected rows! 864 */ 865 public function CleanupLogdataByDate( $nDateTimeStamp ) 866 { 867 global $querycount, $dbmapping; 868 $szTableType = $this->_logStreamConfigObj->DBTableType; 869 870 // Set default rowcount 871 $rowcount = null; 872 873 // Perform if Connection is true! 874 if ( $this->_dbhandle != null ) 875 { 876 // --- Init Filters if necessary! 877 if ( $this->_filters == null ) 878 $this->SetFilter( "" ); // This will init filters! 879 880 // Create SQL Where Clause! 881 $this->CreateSQLWhereClause(); 882 // --- 883 884 // --- Add default WHERE clause 885 if ( strlen($this->_SQLwhereClause) > 0 ) 886 $szWhere = $this->_SQLwhereClause; 887 else 888 $szWhere = ""; 889 890 // Add Datefilter if necessary! 891 if ( $nDateTimeStamp > 0 ) 892 { 893 if ( strlen($szWhere) > 0 ) 894 $szWhere .= " AND "; 895 else 896 $szWhere = " WHERE "; 897 898 // Append Date Filter! 899 $szWhere .= " UNIX_TIMESTAMP(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_DATE] . ") < " . $nDateTimeStamp; 900 } 901 // --- 902 903 // DELETE DATA NOW! 904 $szSql = "DELETE FROM `" . $this->_logStreamConfigObj->DBTableName . "`" . $szWhere; 905 OutputDebugMessage("LogStreamDB|CleanupLogdataByDate: Created SQL Query:<br>" . $szSql, DEBUG_DEBUG); 906 $myQuery = mysqli_query($this->_dbhandle, $szSql); 907 if ($myQuery) 908 { 909 // Get affected rows and return! 910 $rowcount = mysqli_affected_rows($this->_dbhandle); 911 912 // Reset AUTO_INCREMENT if all records were deleted! 913 if ( $nDateTimeStamp == 0 ) 914 { 915 $szSql = "ALTER TABLE " . $this->_logStreamConfigObj->DBTableName . " AUTO_INCREMENT=0"; 916 $myQuery = mysqli_query($this->_dbhandle, $szSql); 917 // error occured, output DEBUG message 918 if (!$myQuery) 919 $this->PrintDebugError("CleanupLogdataByDate failed to reset AUTO_INCREMENT for '" . $this->_logStreamConfigObj->DBTableName . "' table. "); 920 } 921 922 // Free result not needed here! 923 //mysqli_free_result ($myQuery); 924 } 925 else 926 { 927 // error occured, output DEBUG message 928 $this->PrintDebugError("CleanupLogdataByDate failed with SQL Statement ' " . $szSql . " '"); 929 } 930 } 931 932 //return affected rows 933 return $rowcount; 934 } 935 936 937 /* 938 * Implementation of the UpdateAllMessageChecksum 939 * 940 * Update all missing checksum properties in the current database 941 */ 942 public function UpdateAllMessageChecksum( ) 943 { 944 global $querycount, $dbmapping; 945 $szTableType = $this->_logStreamConfigObj->DBTableType; 946 947 // UPDATE DATA NOW! 948 $szSql = "UPDATE " . $this->_logStreamConfigObj->DBTableName . 949 " SET " . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . " = crc32(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_MESSAGE] . ") " . 950 " WHERE " . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . " IS NULL OR " . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . " = 0"; 951 952 // Output Debug Informations 953 OutputDebugMessage("LogStreamDB|UpdateAllMessageChecksum: Running Created SQL Query:<br>" . $szSql, DEBUG_ULTRADEBUG); 954 955 // Running SQL Query 956 $myQuery = mysqli_query($this->_dbhandle, $szSql); 957 if ($myQuery) 958 { 959 // Debug Output 960 OutputDebugMessage("LogStreamDB|UpdateAllMessageChecksum: Successfully updated Checksum of '" . mysqli_affected_rows($this->_dbhandle) . "' datarecords", DEBUG_INFO); 961 962 // Return success 963 return SUCCESS; 964 } 965 else 966 { 967 // error occured, output DEBUG message 968 $this->PrintDebugError("SaveMessageChecksum failed with SQL Statement ' " . $szSql . " '"); 969 970 // Failed 971 return ERROR; 972 } 973 } 974 975 976 /* 977 * Implementation of the SaveMessageChecksum 978 * 979 * Creates an database UPDATE Statement and performs it! 980 */ 981 public function SaveMessageChecksum( $arrProperitesIn ) 982 { 983 global $querycount, $dbmapping; 984 $szTableType = $this->_logStreamConfigObj->DBTableType; 985 986 if ( isset($arrProperitesIn[SYSLOG_UID]) && isset($arrProperitesIn[MISC_CHECKSUM]) && isset($dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM]) ) 987 { 988 // UPDATE DATA NOW! 989 $szSql = "UPDATE " . $this->_logStreamConfigObj->DBTableName . 990 " SET " . $dbmapping[$szTableType]['DBMAPPINGS'][MISC_CHECKSUM] . " = " . $arrProperitesIn[MISC_CHECKSUM] . 991 " WHERE " . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . " = " . $arrProperitesIn[SYSLOG_UID]; 992 $myQuery = mysqli_query($this->_dbhandle, $szSql); 993 if ($myQuery) 994 { 995 // Return success 996 return SUCCESS; 997 } 998 else 999 { 1000 // error occured, output DEBUG message 1001 $this->PrintDebugError("SaveMessageChecksum failed with SQL Statement ' " . $szSql . " '"); 1002 1003 // Failed 1004 return ERROR; 1005 } 1006 } 1007 else 1008 // Missing important properties 1009 return ERROR; 1010 } 1011 1012 1013 /** 1014 * Implementation of ConsolidateItemListByField 1015 * 1016 * In the native MYSQL Logstream, the database will do most of the work 1017 * 1018 * @return integer Error stat 1019 */ 1020 public function ConsolidateItemListByField($szConsFieldId, $nRecordLimit, $szSortFieldId, $nSortingOrder) 1021 { 1022 global $content, $dbmapping, $fields; 1023 1024 // Copy helper variables, this is just for better readability 1025 $szTableType = $this->_logStreamConfigObj->DBTableType; 1026 1027 // Check if fields are available 1028 if ( !isset($dbmapping[$szTableType]['DBMAPPINGS'][$szConsFieldId]) || !isset($dbmapping[$szTableType]['DBMAPPINGS'][$szSortFieldId]) ) 1029 return ERROR_DB_DBFIELDNOTFOUND; 1030 1031 // --- Set Options 1032 $nConsFieldType = $fields[$szConsFieldId]['FieldType']; 1033 1034 if ( $nSortingOrder == SORTING_ORDER_DESC ) 1035 $szSortingOrder = "DESC"; 1036 else 1037 $szSortingOrder = "ASC"; 1038 // --- 1039 1040 // --- Set DB Field names 1041 $myDBConsFieldName = $dbmapping[$szTableType]['DBMAPPINGS'][$szConsFieldId]; 1042 $myDBGroupByFieldName = $myDBConsFieldName; 1043 $myDBQueryFields = $myDBConsFieldName . ", "; 1044 1045 // Set Sorted Field 1046 if ( $szConsFieldId == $szSortFieldId ) 1047 $myDBSortedFieldName = "itemcount"; 1048 else 1049 $myDBSortedFieldName = $szSortFieldId; 1050 // --- 1051 1052 // Special handling for date fields 1053 if ( $nConsFieldType == FILTER_TYPE_DATE ) 1054 { 1055 // Helper variable for the select statement 1056 $mySelectFieldName = $myDBGroupByFieldName . "grouped"; 1057 $myDBQueryFieldName = "DATE( " . $myDBConsFieldName . ") AS " . $myDBGroupByFieldName ; 1058 } 1059 1060 // Set Limit String 1061 if ( $nRecordLimit > 0 ) 1062 $szLimitSql = " LIMIT " . $nRecordLimit; 1063 else 1064 $szLimitSql = ""; 1065 1066 // Create SQL Where Clause! 1067 if ( $this->_SQLwhereClause == "" ) 1068 { 1069 $res = $this->CreateSQLWhereClause(); 1070 if ( $res != SUCCESS ) 1071 return $res; 1072 } 1073 1074 // Create SQL String now! 1075 $szSql = "SELECT " . 1076 $myDBQueryFields . 1077 "count(" . $myDBConsFieldName . ") as itemcount " . 1078 " FROM `" . $this->_logStreamConfigObj->DBTableName . "`" . 1079 $this->_SQLwhereClause . 1080 " GROUP BY " . $myDBGroupByFieldName . 1081 " ORDER BY " . $myDBSortedFieldName . " " . $szSortingOrder . 1082 $szLimitSql ; 1083 1084 // Output Debug Informations 1085 OutputDebugMessage("LogStreamDB|ConsolidateItemListByField: Running Created SQL Query:<br>" . $szSql, DEBUG_ULTRADEBUG); 1086 1087 // Perform Database Query 1088 $myquery = mysqli_query($this->_dbhandle, $szSql); 1089 if ( !$myquery ) { 1090 $this->PrintDebugError("Invalid SQL: ".$szSql); 1091 return ERROR_DB_QUERYFAILED; 1092 } 1093 1094 // Initialize Array variable 1095 $aResult = array(); 1096 1097 // read data records 1098 while ($myRow = mysqli_fetch_array($myquery, MYSQLI_ASSOC)) 1099 { 1100 // Keys need to be converted into lowercase! 1101 $myRow = array_change_key_case($myRow, CASE_LOWER); 1102 1103 // Create new row 1104 $aNewRow = array(); 1105 1106 foreach ( $myRow as $myFieldName => $myFieldValue ) 1107 { 1108 if ( $myFieldName == $dbmapping[$szTableType]['DBMAPPINGS'][$szConsFieldId] ) 1109 $aNewRow[$szConsFieldId] = $myFieldValue; 1110 else 1111 $aNewRow[$myFieldName] = $myFieldValue; 1112 } 1113 1114 // Add new row to result 1115 $aResult[] = $aNewRow; 1116 } 1117 1118 // return finished array 1119 if ( count($aResult) > 0 ) 1120 return $aResult; 1121 else 1122 return ERROR_NOMORERECORDS; 1123 } 1124 1125 1126 /** 1127 * Implementation of ConsolidateDataByField 1128 * 1129 * In the native MYSQL Logstream, the database will do most of the work 1130 * 1131 * @return integer Error stat 1132 */ 1133 public function ConsolidateDataByField($szConsFieldId, $nRecordLimit, $szSortFieldId, $nSortingOrder, $aIncludeCustomFields = null, $bIncludeLogStreamFields = false, $bIncludeMinMaxDateFields = false) 1134 { 1135 global $content, $dbmapping, $fields; 1136 1137 // Copy helper variables, this is just for better readability 1138 $szTableType = $this->_logStreamConfigObj->DBTableType; 1139 1140 // Check if fields are available 1141 if ( !isset($dbmapping[$szTableType]['DBMAPPINGS'][$szConsFieldId]) || !isset($dbmapping[$szTableType]['DBMAPPINGS'][$szSortFieldId]) ) 1142 return ERROR_DB_DBFIELDNOTFOUND; 1143 1144 // --- Set Options 1145 $nConsFieldType = $fields[$szConsFieldId]['FieldType']; 1146 1147 if ( $nSortingOrder == SORTING_ORDER_DESC ) 1148 $szSortingOrder = "DESC"; 1149 else 1150 $szSortingOrder = "ASC"; 1151 // --- 1152 1153 // --- Set DB Field names 1154 $myDBConsFieldName = $dbmapping[$szTableType]['DBMAPPINGS'][$szConsFieldId]; 1155 $myDBGroupByFieldName = $myDBConsFieldName; 1156 1157 // Check which fields to include 1158 if ( $aIncludeCustomFields != null ) 1159 { 1160 $myDBQueryFields = ""; 1161 foreach ( $aIncludeCustomFields as $myFieldName ) 1162 { 1163 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myFieldName]) ) 1164 $myDBQueryFields .= $dbmapping[$szTableType]['DBMAPPINGS'][$myFieldName] . ", "; 1165 } 1166 1167 // Append Sortingfield 1168 if ( !in_array($szConsFieldId, $aIncludeCustomFields) ) 1169 $myDBQueryFields .= $myDBConsFieldName . ", "; 1170 } 1171 else if ( $bIncludeLogStreamFields ) 1172 { 1173 $myDBQueryFields = ""; 1174 foreach ( $this->_arrProperties as $myFieldName ) 1175 { 1176 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myFieldName]) ) 1177 $myDBQueryFields .= $dbmapping[$szTableType]['DBMAPPINGS'][$myFieldName] . ", "; 1178 } 1179 } 1180 else // Only Include ConsolidateField 1181 $myDBQueryFields = $myDBConsFieldName . ", "; 1182 1183 // Add Min and Max fields for DATE if desired 1184 if ( $bIncludeMinMaxDateFields ) 1185 { 1186 $myDBQueryFields .= "Min(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_DATE] . ") as firstoccurrence_date, "; 1187 $myDBQueryFields .= "Max(" . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_DATE] . ") as lastoccurrence_date, "; 1188 } 1189 1190 if ( $szConsFieldId == $szSortFieldId ) 1191 $myDBSortedFieldName = "itemcount"; 1192 else 1193 $myDBSortedFieldName = $szSortFieldId; 1194 // --- 1195 1196 // Special handling for date fields 1197 if ( $nConsFieldType == FILTER_TYPE_DATE ) 1198 { 1199 // Helper variable for the select statement 1200 $mySelectFieldName = $myDBGroupByFieldName . "grouped"; 1201 $myDBQueryFieldName = "DATE( " . $myDBConsFieldName . ") AS " . $myDBGroupByFieldName ; 1202 } 1203 1204 // Set Limit String 1205 if ( $nRecordLimit > 0 ) 1206 $szLimitSql = " LIMIT " . $nRecordLimit; 1207 else 1208 $szLimitSql = ""; 1209 1210 // Create SQL Where Clause! 1211 if ( strlen($this->_SQLwhereClause) <= 0 ) 1212 { 1213 $res = $this->CreateSQLWhereClause(); 1214 if ( $res != SUCCESS ) 1215 return $res; 1216 } 1217 1218 // Create SQL String now! 1219 $szSql = "SELECT " . 1220 $myDBQueryFields . 1221 "count(" . $myDBConsFieldName . ") as itemcount " . 1222 " FROM `" . $this->_logStreamConfigObj->DBTableName . "`" . 1223 $this->_SQLwhereClause . 1224 " GROUP BY " . $myDBGroupByFieldName . 1225 " ORDER BY " . $myDBSortedFieldName . " " . $szSortingOrder . 1226 $szLimitSql ; 1227 1228 // Output Debug Informations 1229 OutputDebugMessage("LogStreamDB|ConsolidateDataByField: Running Created SQL Query:<br>" . $szSql, DEBUG_ULTRADEBUG); 1230 1231 // Perform Database Query 1232 $myquery = mysqli_query($this->_dbhandle, $szSql); 1233 if ( !$myquery ) { 1234 $this->PrintDebugError("Invalid SQL: ".$szSql); 1235 return ERROR_DB_QUERYFAILED; 1236 } 1237 1238 // Initialize Array variable 1239 $aResult = array(); 1240 1241 // read data records 1242 while ($myRow = mysqli_fetch_array($myquery, MYSQLI_ASSOC)) 1243 { 1244 // Keys need to be converted into lowercase! 1245 $myRow = array_change_key_case($myRow, CASE_LOWER); 1246 1247 // Create new row 1248 $aNewRow = array(); 1249 1250 foreach ( $myRow as $myFieldName => $myFieldValue ) 1251 { 1252 $myFieldID = $this->GetFieldIDbyDatabaseMapping($szTableType, $myFieldName); 1253 $aNewRow[ $myFieldID ] = $myFieldValue; 1254 } 1255 // Add new row to result 1256 $aResult[] = $aNewRow; 1257 } 1258 1259 // return finished array 1260 if ( count($aResult) > 0 ) 1261 return $aResult; 1262 else 1263 return ERROR_NOMORERECORDS; 1264 } 1265 1266 /** 1267 * Implementation of GetCountSortedByField 1268 * 1269 * In the native MYSQL Logstream, the database will do most of the work 1270 * 1271 * @return integer Error stat 1272 */ 1273 public function GetCountSortedByField($szFieldId, $nFieldType, $nRecordLimit) 1274 { 1275 global $content, $dbmapping; 1276 1277 // Copy helper variables, this is just for better readability 1278 $szTableType = $this->_logStreamConfigObj->DBTableType; 1279 1280 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$szFieldId]) ) 1281 { 1282 // Set DB Field name first! 1283 $myDBFieldName = $dbmapping[$szTableType]['DBMAPPINGS'][$szFieldId]; 1284 $myDBQueryFieldName = $myDBFieldName; 1285 $mySelectFieldName = $myDBFieldName; 1286 1287 // Special handling for date fields 1288 if ( $nFieldType == FILTER_TYPE_DATE ) 1289 { 1290 // Helper variable for the select statement 1291 $mySelectFieldName = $mySelectFieldName . "grouped"; 1292 $myDBQueryFieldName = "DATE( " . $myDBFieldName . ") AS " . $mySelectFieldName ; 1293 } 1294 1295 // Create SQL Where Clause! 1296 if ( $this->_SQLwhereClause == "" ) 1297 { 1298 $res = $this->CreateSQLWhereClause(); 1299 if ( $res != SUCCESS ) 1300 return $res; 1301 } 1302 1303 // Create SQL String now! 1304 $szSql = "SELECT " . 1305 $myDBQueryFieldName . ", " . 1306 "count(" . $myDBFieldName . ") as totalcount " . 1307 " FROM `" . $this->_logStreamConfigObj->DBTableName . "`" . 1308 $this->_SQLwhereClause . 1309 " GROUP BY " . $mySelectFieldName . 1310 " ORDER BY totalcount DESC" . 1311 " LIMIT " . $nRecordLimit; 1312 1313 // Perform Database Query 1314 $myquery = mysqli_query($this->_dbhandle, $szSql); 1315 if ( !$myquery ) { 1316 $this->PrintDebugError("Invalid SQL: ".$szSql); 1317 return ERROR_DB_QUERYFAILED; 1318 } 1319 1320 // Initialize Array variable 1321 $aResult = array(); 1322 1323 // read data records 1324 while ($myRow = mysqli_fetch_array($myquery, MYSQLI_ASSOC)) 1325 { 1326 // Keys need to be converted into lowercase! 1327 $myRow = array_change_key_case($myRow, CASE_LOWER); 1328 1329 // Set totalcount Result 1330 $aResult[ $myRow[$mySelectFieldName] ] = $myRow['totalcount']; 1331 } 1332 1333 // return finished array 1334 if ( count($aResult) > 0 ) 1335 return $aResult; 1336 else 1337 return ERROR_NOMORERECORDS; 1338 } 1339 else 1340 { 1341 // return error code, field mapping not found 1342 return ERROR_DB_DBFIELDNOTFOUND; 1343 } 1344 } 1345 1346 1347 1348 /* 1349 * ============= Beginn of private functions ============= 1350 */ 1351 1352 /* 1353 * This function expects the filters to already being set earlier. 1354 * Otherwise no usual WHERE Clause can be created! 1355 */ 1356 private function CreateSQLWhereClause() 1357 { 1358 if ( $this->_filters != null ) 1359 { 1360 global $dbmapping; 1361 $szTableType = $this->_logStreamConfigObj->DBTableType; 1362 1363 // Reset WhereClause 1364 $this->_SQLwhereClause = ""; 1365 1366 // --- Build Query Array 1367 $arrayQueryProperties = $this->_arrProperties; 1368 if ( isset($this->_arrFilterProperties) && $this->_arrFilterProperties != null) 1369 { 1370 foreach ( $this->_arrFilterProperties as $filterproperty ) 1371 { 1372 if ( $this->_arrProperties == null || !in_array($filterproperty, $this->_arrProperties) ) 1373 $arrayQueryProperties[] = $filterproperty; 1374 } 1375 } 1376 // --- 1377 1378 // Loop through all available properties 1379 foreach( $arrayQueryProperties as $propertyname ) 1380 { 1381 // If the property exists in the filter array, we have something to filter for ^^! 1382 if ( array_key_exists($propertyname, $this->_filters) ) 1383 { 1384 // Process all filters 1385 foreach( $this->_filters[$propertyname] as $myfilter ) 1386 { 1387 // Only perform if database mapping is available for this filter! 1388 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$propertyname]) ) 1389 { 1390 switch( $myfilter[FILTER_TYPE] ) 1391 { 1392 case FILTER_TYPE_STRING: 1393 // --- Either make a LIKE or a equal query! 1394 if ( $myfilter[FILTER_MODE] & FILTER_MODE_SEARCHFULL ) 1395 { 1396 // Set addnot to nothing 1397 $addnod = ""; 1398 1399 // --- Check if user wants to include or exclude! 1400 if ( $myfilter[FILTER_MODE] & FILTER_MODE_INCLUDE) 1401 { 1402 $szSearchBegin = " = '"; 1403 $szSearchEnd = "' "; 1404 } 1405 else 1406 { 1407 $szSearchBegin = " <> '"; 1408 $szSearchEnd = "' "; 1409 } 1410 // --- 1411 } 1412 else if ( $myfilter[FILTER_MODE] & FILTER_MODE_SEARCHREGEX ) 1413 { 1414 // --- Check if user wants to include or exclude! 1415 if ( $myfilter[FILTER_MODE] & FILTER_MODE_INCLUDE) 1416 $addnod = ""; 1417 else 1418 $addnod = " NOT"; 1419 // --- 1420 1421 $szSearchBegin = " REGEXP '"; 1422 $szSearchEnd = "' "; 1423 } 1424 else 1425 { 1426 // --- Check if user wants to include or exclude! 1427 if ( $myfilter[FILTER_MODE] & FILTER_MODE_INCLUDE) 1428 $addnod = ""; 1429 else 1430 $addnod = " NOT"; 1431 // --- 1432 1433 $szSearchBegin = " LIKE '%"; 1434 $szSearchEnd = "%' "; 1435 } 1436 // --- 1437 1438 // --- If Syslog message, we have AND handling, otherwise OR! 1439 if ( $propertyname == SYSLOG_MESSAGE ) 1440 $addor = " AND "; 1441 else 1442 { 1443 // If we exclude filters, we need to combine with AND 1444 if ( $myfilter[FILTER_MODE] & FILTER_MODE_INCLUDE) 1445 $addor = " OR "; 1446 else 1447 $addor = " AND "; 1448 } 1449 // --- 1450 1451 // Now Create LIKE Filters 1452 if ( isset($tmpfilters[$propertyname]) ) 1453 $tmpfilters[$propertyname][FILTER_VALUE] .= $addor . $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . $addnod . $szSearchBegin . DB_RemoveBadChars($myfilter[FILTER_VALUE]) . $szSearchEnd; 1454 else 1455 { 1456 $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_STRING; 1457 $tmpfilters[$propertyname][FILTER_VALUE] = $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . $addnod . $szSearchBegin . DB_RemoveBadChars($myfilter[FILTER_VALUE]) . $szSearchEnd; 1458 } 1459 break; 1460 case FILTER_TYPE_NUMBER: 1461 // --- Check if user wants to include or exclude! 1462 if ( $myfilter[FILTER_MODE] & FILTER_MODE_EXCLUDE ) 1463 { 1464 // Add to filterset 1465 $szArrayKey = $propertyname . "-NOT"; 1466 if ( isset($tmpfilters[$szArrayKey]) ) 1467 $tmpfilters[$szArrayKey][FILTER_VALUE] .= ", " . $myfilter[FILTER_VALUE]; 1468 else 1469 { 1470 $tmpfilters[$szArrayKey][FILTER_TYPE] = FILTER_TYPE_NUMBER; 1471 $tmpfilters[$szArrayKey][FILTER_VALUE] = $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " NOT IN (" . DB_RemoveBadChars($myfilter[FILTER_VALUE]); 1472 } 1473 } 1474 else 1475 { 1476 // Add to filterset 1477 if ( isset($tmpfilters[$propertyname]) ) 1478 $tmpfilters[$propertyname][FILTER_VALUE] .= ", " . $myfilter[FILTER_VALUE]; 1479 else 1480 { 1481 $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_NUMBER; 1482 $tmpfilters[$propertyname][FILTER_VALUE] = $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " IN (" . DB_RemoveBadChars($myfilter[FILTER_VALUE]); 1483 } 1484 } 1485 // --- 1486 break; 1487 case FILTER_TYPE_DATE: 1488 if ( isset($tmpfilters[$propertyname]) ) 1489 $tmpfilters[$propertyname][FILTER_VALUE] .= " AND "; 1490 else 1491 { 1492 $tmpfilters[$propertyname][FILTER_VALUE] = ""; 1493 $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_DATE; 1494 } 1495 1496 if ( $myfilter[FILTER_DATEMODE] == DATEMODE_LASTX ) 1497 { 1498 // Get current timestamp 1499 $nNowTimeStamp = time(); 1500 1501 if ( $myfilter[FILTER_VALUE] == DATE_LASTX_HOUR ) 1502 $nNowTimeStamp -= 60 * 60; // One Hour! 1503 else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_12HOURS ) 1504 $nNowTimeStamp -= 60 * 60 * 12; // 12 Hours! 1505 else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_24HOURS ) 1506 $nNowTimeStamp -= 60 * 60 * 24; // 24 Hours! 1507 else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_7DAYS ) 1508 $nNowTimeStamp -= 60 * 60 * 24 * 7; // 7 days 1509 else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_31DAYS ) 1510 $nNowTimeStamp -= 60 * 60 * 24 * 31; // 31 days 1511 else 1512 { 1513 // Set filter to unknown and Abort in this case! 1514 $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_UNKNOWN; 1515 break; 1516 } 1517 1518 // Append filter 1519 $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " > '" . date("Y-m-d H:i:s", $nNowTimeStamp) . "'"; 1520 } 1521 else if ( $myfilter[FILTER_DATEMODE] == DATEMODE_RANGE_FROM ) 1522 { 1523 // Obtain Event struct for the time! 1524 $myeventtime = GetEventTime($myfilter[FILTER_VALUE]); 1525 $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " > '" . date("Y-m-d H:i:s", $myeventtime[EVTIME_TIMESTAMP]) . "'"; 1526 } 1527 else if ( $myfilter[FILTER_DATEMODE] == DATEMODE_RANGE_TO ) 1528 { 1529 // Obtain Event struct for the time! 1530 $myeventtime = GetEventTime($myfilter[FILTER_VALUE]); 1531 $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " < '" . date("Y-m-d H:i:s", $myeventtime[EVTIME_TIMESTAMP]) . "'"; 1532 } 1533 else if ( $myfilter[FILTER_DATEMODE] == DATEMODE_RANGE_DATE ) 1534 { 1535 // Obtain Event struct for the time! 1536 $myeventtime = GetEventTime($myfilter[FILTER_VALUE]); 1537 $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " > '" . date("Y-m-d H:i:s", $myeventtime[EVTIME_TIMESTAMP]) . "' AND " . 1538 $dbmapping[$szTableType]['DBMAPPINGS'][$propertyname] . " < '" . date("Y-m-d H:i:s", ($myeventtime[EVTIME_TIMESTAMP]+86400) ) . "'"; 1539 } 1540 1541 break; 1542 default: 1543 // Nothing to do! 1544 break; 1545 } 1546 } 1547 else 1548 { 1549 // Check how to treat not found db mappings / filters 1550 if ( GetConfigSetting("TreatNotFoundFiltersAsTrue", 0, CFGLEVEL_USER) == 0 ) 1551 return ERROR_DB_DBFIELDNOTFOUND; 1552 } 1553 } 1554 } 1555 } 1556 1557 // Check and combine all filters now! 1558 if ( isset($tmpfilters) ) 1559 { 1560 // Append filters 1561 foreach( $tmpfilters as $tmpfilter ) 1562 { 1563 // Init WHERE or Append AND 1564 if ( strlen($this->_SQLwhereClause) > 0 ) 1565 $this->_SQLwhereClause .= " AND "; 1566 else 1567 $this->_SQLwhereClause = " WHERE "; 1568 1569 switch( $tmpfilter[FILTER_TYPE] ) 1570 { 1571 case FILTER_TYPE_STRING: 1572 $this->_SQLwhereClause .= "( " . $tmpfilter[FILTER_VALUE] . ") "; 1573 break; 1574 case FILTER_TYPE_NUMBER: 1575 $this->_SQLwhereClause .= $tmpfilter[FILTER_VALUE] . ") "; 1576 break; 1577 case FILTER_TYPE_DATE: 1578 $this->_SQLwhereClause .= $tmpfilter[FILTER_VALUE]; 1579 break; 1580 default: 1581 // Should not happen, wrong filters! 1582 // We add a dummy into the where clause, just as a place holder 1583 $this->_SQLwhereClause .= " 1=1 "; 1584 break; 1585 } 1586 } 1587 } 1588 1589// echo $this->_SQLwhereClause; 1590 //$dbmapping[$szTableType][SYSLOG_UID] 1591 } 1592 else // No filters means nothing to do! 1593 return SUCCESS; 1594 } 1595 1596 /* 1597 * Destroy the SQL QUery! 1598 */ 1599 private function DestroyMainSQLQuery() 1600 { 1601 // create query if necessary! 1602 if ( $this->_myDBQuery != null ) 1603 { 1604 // Free Query ressources 1605 mysqli_free_result ($this->_myDBQuery); 1606 $this->_myDBQuery = null; 1607 } 1608 1609 // return success state if reached this point! 1610 return SUCCESS; 1611 } 1612 1613 /* 1614 * This helper function will read the next records into the buffer. 1615 */ 1616 private function ReadNextRecordsFromDB($uID) 1617 { 1618 global $querycount; 1619 1620 // Clear SQL Query first! 1621 $this->DestroyMainSQLQuery(); 1622 1623 // return error if there was one! 1624 if ( ($res = $this->CreateMainSQLQuery($uID)) != SUCCESS ) 1625 return $res; 1626 1627 // Append LIMIT clause 1628// $szSql .= " LIMIT " . $this->_currentRecordStart . ", " . $this->_logStreamConfigObj->RecordsPerQuery; 1629 1630 // Copy rows into the buffer! 1631 $iBegin = $this->_currentRecordNum; 1632 while ($myRow = mysqli_fetch_array($this->_myDBQuery, MYSQLI_ASSOC)) 1633 { 1634 // Check if result was successfull! 1635 if ( $myRow === FALSE || !$myRow ) 1636 break; 1637 1638 // Keys need to be converted into lowercase! 1639 $this->bufferedRecords[$iBegin] = array_change_key_case($myRow, CASE_LOWER); 1640 $iBegin++; 1641 } 1642 1643 // --- Check if results were found 1644 if ( $iBegin == $this->_currentRecordNum ) 1645 return ERROR_NOMORERECORDS; 1646 // --- 1647 1648 // Free Query ressources 1649// mysqli_free_result ($myquery); 1650 1651 // Only obtain count if enabled and not done before 1652 if ( $this->_logStreamConfigObj->DBEnableRowCounting && $this->_totalRecordCount == -1 ) 1653 { 1654 $this->_totalRecordCount = $this->GetRowCountFromTable(); 1655 1656 if ( $this->_totalRecordCount <= 0 ) 1657 return ERROR_NOMORERECORDS; 1658 } 1659 1660 // Increment for the Footer Stats 1661 $querycount++; 1662 1663 // return success state if reached this point! 1664 return SUCCESS; 1665 } 1666 1667 /* 1668 * Create the SQL QUery! 1669 */ 1670 private function CreateMainSQLQuery($uID) 1671 { 1672 global $querycount; 1673 1674 // Get SQL Statement 1675 $szSql = $this->CreateSQLStatement($uID); 1676 1677 // --- Append LIMIT 1678 $szSql .= " LIMIT " . $this->_logStreamConfigObj->RecordsPerQuery; 1679 // --- 1680 1681 // Perform Database Query 1682 $this->_myDBQuery = mysqli_query($this->_dbhandle, $szSql); 1683 if ( !$this->_myDBQuery ) 1684 { 1685 // Check if a field is missing! 1686 if ( mysqli_errno($this->_dbhandle) == 1054 ) 1687 { 1688 // Handle missing field and try again! 1689 if ( $this->HandleMissingField() == SUCCESS ) 1690 { 1691 $this->_myDBQuery = mysqli_query($this->_dbhandle, $szSql); 1692 if ( !$this->_myDBQuery ) { 1693 $this->PrintDebugError("Invalid SQL: ".$szSql); 1694 return ERROR_DB_QUERYFAILED; 1695 } 1696 } 1697 else // Failed to add field dynamically 1698 return ERROR_DB_QUERYFAILED; 1699 } 1700 else 1701 { 1702 $this->PrintDebugError("Invalid SQL: ".$szSql); 1703 return ERROR_DB_QUERYFAILED; 1704 } 1705 } 1706 else 1707 { 1708 // Skip one entry in this case 1709 if ( $this->_currentRecordStart > 0 ) 1710 { 1711 // Throw away 1712 $myRow = mysqli_fetch_array($this->_myDBQuery, MYSQLI_ASSOC); 1713 } 1714 } 1715 1716 // Increment for the Footer Stats 1717 $querycount++; 1718 1719 // Output Debug Informations 1720 OutputDebugMessage("LogStreamDB|CreateMainSQLQuery: Created SQL Query:<br>" . $szSql, DEBUG_DEBUG); 1721 1722 // return success state if reached this point! 1723 return SUCCESS; 1724 } 1725 1726 /* 1727 * Creates the SQL Statement we are going to use! 1728 */ 1729 private function CreateSQLStatement($uID, $includeFields = true) 1730 { 1731 global $dbmapping; 1732 1733 // Copy helper variables, this is just for better readability 1734 $szTableType = $this->_logStreamConfigObj->DBTableType; 1735 $szSortColumn = $this->_logStreamConfigObj->SortColumn; 1736 1737 // Create Basic SQL String 1738 if ( $this->_logStreamConfigObj->DBEnableRowCounting ) // with SQL_CALC_FOUND_ROWS 1739 $sqlString = "SELECT SQL_CALC_FOUND_ROWS " . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID]; 1740 else // without row calc 1741 $sqlString = "SELECT " . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID]; 1742 1743 // Append fields if needed 1744 if ( $includeFields && $this->_arrProperties != null ) 1745 { 1746 // Loop through all requested fields 1747 foreach ( $this->_arrProperties as $myproperty ) 1748 { 1749 // SYSLOG_UID already added! 1750 if ( $myproperty != SYSLOG_UID && isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) ) 1751 { 1752 // Append field! 1753 $sqlString .= ", " . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]; 1754 } 1755 } 1756 } 1757 1758 // Append FROM 'table'! 1759 $sqlString .= " FROM `" . $this->_logStreamConfigObj->DBTableName . "`"; 1760 1761 // Append precreated where clause 1762 $sqlString .= $this->_SQLwhereClause; 1763 1764 // Append UID QUERY! 1765 if ( $uID != -1 ) 1766 { 1767 if ( $this->_readDirection == EnumReadDirection::Forward ) 1768 $myOperator = ">="; 1769 else 1770 $myOperator = "<="; 1771 1772 if ( strlen($this->_SQLwhereClause) > 0 ) 1773 $sqlString .= " AND " . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . " $myOperator $uID"; 1774 else 1775 $sqlString .= " WHERE " . $dbmapping[$szTableType]['DBMAPPINGS'][SYSLOG_UID] . " $myOperator $uID"; 1776 } 1777 1778 // Append ORDER clause 1779 if ( $this->_readDirection == EnumReadDirection::Forward ) 1780 $sqlString .= " ORDER BY " . $dbmapping[$szTableType]['DBMAPPINGS'][$szSortColumn]; 1781 else if ( $this->_readDirection == EnumReadDirection::Backward ) 1782 $sqlString .= " ORDER BY " . $dbmapping[$szTableType]['DBMAPPINGS'][$szSortColumn] . " DESC"; 1783 1784 // return SQL result string: 1785 return $sqlString; 1786 } 1787 1788 /* 1789 * Reset record buffer in this function! 1790 */ 1791 private function ResetBufferedRecords() 1792 { 1793 if ( isset($this->bufferedRecords) ) 1794 { 1795 // Loop through all subrecords first! 1796 foreach ($this->bufferedRecords as $mykey => $myrecord) 1797 unset( $this->bufferedRecords[$mykey] ); 1798 1799 // Set buffered records to NULL! 1800 $this->bufferedRecords = null; 1801 } 1802 } 1803 1804 /* 1805 * Helper function to display SQL Errors for now! 1806 */ 1807 private function PrintDebugError($szErrorMsg) 1808 { 1809 global $extraErrorDescription; 1810 1811 $errdesc = mysqli_error($this->_dbhandle); 1812 $errno = mysqli_errno($this->_dbhandle); 1813 1814 $errormsg="$szErrorMsg <br>"; 1815 $errormsg.="Detail error: $errdesc <br>"; 1816 $errormsg.="Error Code: $errno <br>"; 1817 1818 // Add to additional error output 1819 $extraErrorDescription = $errormsg; 1820 1821 //Output! 1822 OutputDebugMessage("LogStreamDB|PrintDebugError: $errormsg", DEBUG_ERROR); 1823 } 1824 1825 /* 1826 * Returns the number of possible records by using a query 1827 */ 1828 private function GetRowCountByString($szQuery) 1829 { 1830 if ($myQuery = mysqli_query($this->_dbhandle, $szQuery)) 1831 { 1832 $num_rows = mysqli_num_rows($myQuery); 1833 mysqli_free_result ($myQuery); 1834 } 1835 return $num_rows; 1836 } 1837 1838 /* 1839 * Returns the number of possible records by using an existing queryid 1840 */ 1841 private function GetRowCountByQueryID($myQuery) 1842 { 1843 $num_rows = mysqli_num_rows($myQuery); 1844 return $num_rows; 1845 } 1846 1847 /* 1848 * Returns the number of possible records by using a select count statement! 1849 */ 1850 private function GetRowCountFromTable() 1851 { 1852 if ( $myquery = mysqli_query($this->_dbhandle, "Select FOUND_ROWS();") ) 1853 { 1854 // Get first and only row! 1855 $myRow = mysqli_fetch_array($myquery); 1856 1857 // copy row count 1858 $numRows = $myRow[0]; 1859 } 1860 else 1861 $numRows = -1; 1862 1863 // return result! 1864 return $numRows; 1865 } 1866 1867 /* 1868 * Function handles missing database fields automatically! 1869 */ 1870 private function HandleMissingField( $szMissingField = null, $arrProperties = null ) 1871 { 1872 global $dbmapping, $fields; 1873 1874 // Get Err description 1875 $errdesc = mysqli_error($this->_dbhandle); 1876 1877 // Try to get missing field from SQL Error of not specified as argument 1878 if ( $szMissingField == null ) 1879 { 1880 if ( preg_match("/Unknown column '(.*?)' in '(.*?)'$/", $errdesc, $errOutArr ) ) 1881 $szMissingField = $errOutArr[1]; 1882 else 1883 { 1884 $this->PrintDebugError("ER_BAD_FIELD_ERROR - SQL Statement: ". $errdesc); 1885 return ERROR_DB_DBFIELDNOTFOUND; 1886 } 1887 } 1888 1889 // Set Properties to default if NULL 1890 if ( $arrProperties == null ) 1891 $arrProperties = $this->_arrProperties; 1892 1893 // Get Tabletype 1894 $szTableType = $this->_logStreamConfigObj->DBTableType; 1895 1896 // Loop through all fields to see which one is missing! 1897 foreach ( $arrProperties as $myproperty ) 1898 { 1899 if ( isset($dbmapping[$szTableType]['DBMAPPINGS'][$myproperty]) && $szMissingField == $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] ) 1900 { 1901 // Create SQL Numeric field 1902 $szUpdateSql = ""; $szUnsigned = ""; 1903 if ( $fields[$myproperty]['FieldType'] == FILTER_TYPE_NUMBER ) 1904 { 1905 // This will add the checksum field as unsigned automatically! 1906 if ( $myproperty == MISC_CHECKSUM ) 1907 $szUnsigned = "UNSIGNED"; 1908 $szUpdateSql = "ALTER TABLE `" . $this->_logStreamConfigObj->DBTableName . "` ADD `" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "` int(11) " . $szUnsigned . " NOT NULL DEFAULT '0'"; 1909 } 1910 if ( $fields[$myproperty]['FieldType'] == FILTER_TYPE_STRING ) 1911 $szUpdateSql = "ALTER TABLE `" . $this->_logStreamConfigObj->DBTableName . "` ADD `" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "` varchar(60) NOT NULL DEFAULT ''"; 1912 if ( $fields[$myproperty]['FieldType'] == FILTER_TYPE_DATE ) 1913 $szUpdateSql = "ALTER TABLE `" . $this->_logStreamConfigObj->DBTableName . "` ADD `" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'"; 1914 1915 if ( strlen($szUpdateSql) > 0 ) 1916 { 1917 // Update Table schema now! 1918 $myQuery = mysqli_query($this->_dbhandle, $szUpdateSql); 1919 if (!$myQuery) 1920 { 1921 // Return failure! 1922 $this->PrintDebugError("ER_BAD_FIELD_ERROR - Dynamically Adding field '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "' with Statement failed: '" . $szUpdateSql . "'"); 1923 return ERROR_DB_ADDDBFIELDFAILED; 1924 } 1925 } 1926 else 1927 { 1928 // Return failure! 1929 $this->PrintDebugError("ER_BAD_FIELD_ERROR - Field '" . $dbmapping[$szTableType]['DBMAPPINGS'][$myproperty] . "' is missing has to be added manually to the database layout!'"); 1930 return ERROR_DB_ADDDBFIELDFAILED; 1931 } 1932 } 1933 } 1934 1935 // Reached this point means success! 1936 return SUCCESS; 1937 } 1938 1939 /* 1940 * Helper function to return a list of Indexes for the logstream table 1941 */ 1942 private function GetIndexesAsArray() 1943 { 1944 global $querycount; 1945 1946 // Verify database connection (This also opens the database!) 1947 $res = $this->Verify(); 1948 if ( $res != SUCCESS ) 1949 return $res; 1950 1951 // Init Array 1952 $arrIndexKeys = array(); 1953 1954 // Create SQL and Get INDEXES for table! 1955 $szSql = "SHOW INDEX FROM `" . $this->_logStreamConfigObj->DBTableName . "`"; 1956 $myQuery = mysqli_query($this->_dbhandle, $szSql); 1957 if ($myQuery) 1958 { 1959 // Loop through results 1960 while ($myRow = mysqli_fetch_array($myQuery, MYSQLI_ASSOC)) 1961 { 1962 // Add to index keys 1963 $arrIndexKeys[] = strtolower($myRow['Key_name']); 1964 } 1965 1966 // Free query now 1967 mysqli_free_result ($myQuery); 1968 1969 // Increment for the Footer Stats 1970 $querycount++; 1971 } 1972 1973 // return Array 1974 return $arrIndexKeys; 1975 } 1976 1977 1978 /* 1979 * Helper function to return a list of Fields from the logstream table 1980 */ 1981 private function GetFieldsAsArray() 1982 { 1983 global $querycount; 1984 1985 // Verify database connection (This also opens the database!) 1986 $res = $this->Verify(); 1987 if ( $res != SUCCESS ) 1988 return $res; 1989 1990 // Init Array 1991 $arrFieldKeys = array(); 1992 1993 // Create SQL and Get INDEXES for table! 1994 $szSql = "SHOW FIELDS FROM `" . $this->_logStreamConfigObj->DBTableName . "`"; 1995 $myQuery = mysqli_query($this->_dbhandle, $szSql); 1996 if ($myQuery) 1997 { 1998 // Loop through results 1999 while ($myRow = mysqli_fetch_array($myQuery, MYSQLI_ASSOC)) 2000 { 2001 // Add to index keys 2002 $arrFieldKeys[] = strtolower($myRow['Field']); 2003 } 2004 2005 // Free query now 2006 mysqli_free_result ($myQuery); 2007 2008 // Increment for the Footer Stats 2009 $querycount++; 2010 } 2011 2012 // return Array 2013 return $arrFieldKeys; 2014 } 2015 2016 2017 /* 2018 * Helper function to return a list of Indexes for the logstream table 2019 */ 2020 private function GetTriggersAsArray() 2021 { 2022 global $querycount; 2023 2024 // Verify database connection (This also opens the database!) 2025 $res = $this->Verify(); 2026 if ( $res != SUCCESS ) 2027 return $res; 2028 2029 // Init Array 2030 $arrIndexTriggers = array(); 2031 2032 // Create SQL and Get INDEXES for table! 2033 $szSql = "SHOW TRIGGERS"; 2034 $myQuery = mysqli_query($this->_dbhandle, $szSql); 2035 if ($myQuery) 2036 { 2037 // Loop through results 2038 while ($myRow = mysqli_fetch_array($myQuery, MYSQLI_ASSOC)) 2039 { 2040// print_r ( $myRow ); 2041 // Add to index keys 2042 $arrIndexTriggers[] = strtolower($myRow['Trigger']); 2043 } 2044 2045 // Free query now 2046 mysqli_free_result ($myQuery); 2047 2048 // Increment for the Footer Stats 2049 $querycount++; 2050 } 2051 2052 // return Array 2053 return $arrIndexTriggers; 2054 } 2055 2056// --- End of Class! 2057} 2058 2059?> 2060