diff --git a/src/classes/logstreamconfigpdo.class.php b/src/classes/logstreamconfigpdo.class.php new file mode 100644 index 0000000..13d7125 --- /dev/null +++ b/src/classes/logstreamconfigpdo.class.php @@ -0,0 +1,135 @@ + www.phplogcon.org <- * + * ----------------------------------------------------------------- * + * StreamConfig has the capability to create a specific LogStream * + * object depending on a configured LogStream*Config object. * + * * + * All directives are explained within this file * + * + * Copyright (C) 2008 Adiscon GmbH. + * + * This file is part of phpLogCon. + * + * PhpLogCon is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PhpLogCon is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with phpLogCon. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this + * distribution. + ********************************************************************* +*/ + +// --- Avoid directly accessing this file! +if ( !defined('IN_PHPLOGCON') ) +{ + die('Hacking attempt'); + exit; +} +// --- + +class LogStreamConfigPDO extends LogStreamConfig { + public $DBServer = 'localhost'; + public $DBPort = 0; + public $DBName = ''; + public $DBUser = ''; + public $DBPassword = ''; + public $DBType = DB_MYSQL; // Default = MYSQL! + public $DBTableType = 'winsyslog'; // Default = WINSYSLOG DB Layout! + public $DBTableName = 'systemevents'; // Default Tabelname from WINSYSLOG + public $DBEnableRowCounting = true; // Default RowCounting is enabled! + + // Runtime configuration variables + public $RecordsPerQuery = 100; // This will determine how to limit sql statements + public $IDsPerQuery = 5000; // When we query ID's, we read a lot more the datarecords at once! + public $SortColumn = SYSLOG_UID; // Default sorting column + + public function LogStreamFactory($o) + { + // An instance is created, then include the logstreamdisk class as well! + global $gl_root_path; + require_once($gl_root_path . 'classes/logstreampdo.class.php'); + + // return LogStreamDisk instance + return new LogStreamPDO($o); + } + + public function GetPDODatabaseType() + { + switch ($this->DBType) + { + case DB_MYSQL: + return "mysql"; + case DB_MSSQL: + return "odbc"; + case DB_ODBC: + return "odbc"; + case DB_PGSQL: + return "pgsql"; + case DB_OCI: + return "oci"; + case DB_DB2: + return "ibm"; + case DB_FIREBIRD: + return "firebird"; + case DB_INFORMIX: + return "informix"; + case DB_SQLITE: + return "sqlite"; + default: + return ""; + } + } + + public function CreateConnectDSN() + { + switch ($this->DBType) + { + case DB_MYSQL: + $myDsn = 'mysql:host=' . $this->DBServer /*. ',' . $this->DBPort*/ . ';dbname=' . $this->DBName; + break; + case DB_MSSQL: + $myDsn = 'odbc:Driver={SQL Server}; Server=' . $this->DBServer . '; Uid=' . $this->DBUser . '; Pwd=' . $this->DBPassword . '; Database=' . $this->DBName . ';'; + break; + case DB_ODBC: + $myDsn = 'odbc:dsn=' . $this->DBServer. ';uid=' . $this->DBUser . ';pwd=' . $this->DBPassword . ';Database=' . $this->DBName; + break; + case DB_PGSQL: + $myDsn = 'pgsql:host=' . $this->DBServer . ' dbname=' . $this->DBName . ' user=' . $this->DBUser . ' password=' . $this->DBPassword; // port=5432 + break; + case DB_OCI: + $myDsn = 'oci:dbname=' . $this->DBServer . '/' . $this->DBName; + break; + case DB_DB2: + $myDsn = 'ibm:DRIVER={IBM DB2 ODBC DRIVER};DATABASE=' . $this->DBName . '; HOSTNAME=' . $this->DBServer . '; PROTOCOL=TCPIP; UID=' . $this->DBUser . '; PWD=' . $this->DBPassword; // PORT=port ; + break; + case DB_FIREBIRD: + $myDsn = 'firebird:User=' . $this->DBUser . ';Password=' . $this->DBPassword . ';Database=' . $this->DBName . ';DataSource=' . $this->DBServer; //;Port=3050'; + break; + case DB_INFORMIX: + $myDsn = 'informix:host=' . $this->DBServer . '; database=' . $this->DBName . '; server=' . $this->DBServer . '; protocol=onsoctcp; EnableScrollableCursors=1'; + break; + case DB_SQLITE: + $myDsn = 'sqlite:' . $this->DBName; // DBName is the full Path to the sqlite db file + break; + default: + $myDsn = ''; + } + + // return my DSN now! + return $myDsn; + } + + +} +?> diff --git a/src/classes/logstreamdb.class.php b/src/classes/logstreamdb.class.php index 93c073f..1a5748b 100644 --- a/src/classes/logstreamdb.class.php +++ b/src/classes/logstreamdb.class.php @@ -61,16 +61,6 @@ class LogStreamDB extends LogStream { private $_SQLwhereClause = ""; -/* private $_currentOffset = -1; - private $_currentStartPos = -1; - private $_fp = null; - private $_bEOS = false; - - const _BUFFER_length = 8192; - private $_buffer = false; - private $_buffer_length = 0; - private $_p_buffer = -1; -*/ // Constructor public function LogStreamDB($streamConfigObj) { $this->_logStreamConfigObj = $streamConfigObj; @@ -351,8 +341,27 @@ class LogStreamDB extends LogStream { */ public function GetLastPageUID() { - global $querycount; + global $querycount, $dbmapping; + $szTableType = $this->_logStreamConfigObj->DBTableType; + $szSql = "SELECT MIN(" . $dbmapping[$szTableType][SYSLOG_UID] . ") FROM " . $this->_logStreamConfigObj->DBTableName . $this->_SQLwhereClause; + $myQuery = mysql_query($szSql, $this->_dbhandle); + if ($myQuery) + { + // obtain first and only row + $myRow = mysql_fetch_row($myQuery); + $this->_lastPageUID = $myRow[0]; + + // Free query now + mysql_free_result ($myQuery); + + // Increment for the Footer Stats + $querycount++; + } +//echo $szSql . "
" . $this->_lastPageUID; +//exit; + +/* OLD CODE // Obtain last UID of renough records are available! if ( $this->_totalRecordCount > $this->_logStreamConfigObj->_pageCount ) { @@ -378,6 +387,7 @@ class LogStreamDB extends LogStream { // Increment for the Footer Stats $querycount++; } +*/ // finally return result! return $this->_lastPageUID; @@ -561,8 +571,6 @@ class LogStreamDB extends LogStream { //echo $this->_SQLwhereClause; //$dbmapping[$szTableType][SYSLOG_UID] - - //$this->_SQLwhereClause; } else // No filters means nothing to do! return SUCCESS; diff --git a/src/classes/logstreamdisk.class.php b/src/classes/logstreamdisk.class.php index 6984949..99c0ab9 100644 --- a/src/classes/logstreamdisk.class.php +++ b/src/classes/logstreamdisk.class.php @@ -499,6 +499,8 @@ class LogStreamDisk extends LogStream { // Now we move for one page, we do not need to process the syslog messages! $ret = $this->ReadNext($myuid, $tmpArray, false); + +/* OLD CODE if ( $ret == SUCCESS ) { do @@ -507,7 +509,7 @@ class LogStreamDisk extends LogStream { $counter++; } while ( $counter < $this->_logStreamConfigObj->_pageCount && ($ret = $this->ReadNext($myuid, $tmpArray, false)) == SUCCESS ); } - +*/ // Save the current UID as LastPage UID! $this->_lastPageUID = $myuid; diff --git a/src/classes/logstreampdo.class.php b/src/classes/logstreampdo.class.php new file mode 100644 index 0000000..5f94b8a --- /dev/null +++ b/src/classes/logstreampdo.class.php @@ -0,0 +1,803 @@ + www.phplogcon.org <- + * ----------------------------------------------------------------- + * LogStreamPDO provides access to the data through PDO Interface + * + * \version 2.0.0 Init Version + * + * All directives are explained within this file + * + * Copyright (C) 2008 Adiscon GmbH. + * + * This file is part of phpLogCon. + * + * PhpLogCon is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PhpLogCon is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with phpLogCon. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this + * distribution. + ********************************************************************* +*/ + +// --- Avoid directly accessing this file! +if ( !defined('IN_PHPLOGCON') ) +{ + die('Hacking attempt'); + exit; +} +// --- + +// --- Required Includes! +require_once($gl_root_path . 'include/constants_errors.php'); +// --- + +class LogStreamPDO extends LogStream { + private $_dbhandle = null; + + // Helper to store the database records + private $bufferedRecords = null; + private $_currentRecordStart = 0; + private $_currentRecordNum = 0; + private $_totalRecordCount = -1; + private $_previousPageUID = -1; + private $_lastPageUID = -1; + private $_currentPageNumber = -1; + + private $_SQLwhereClause = ""; + + // Constructor + public function LogStreamPDO($streamConfigObj) { + $this->_logStreamConfigObj = $streamConfigObj; + + // Verify if Extension is enabled + if ( extension_loaded('pdo') == 0 ) + DieWithFriendlyErrorMsg("Error, PDO Extensions are not enabled or installed! This Source can not operate."); + + /* + if ( $this->_logStreamConfigObj->DBType == DB_MYSQL ) + { + // Probe if a function exists! + if ( !function_exists("mysql_connect") ) + DieWithFriendlyErrorMsg("Error, MYSQL Extensions are not enabled! Function 'mysql_connect' does not exist."); + } + */ + } + + /** + * Open and verifies the database conncetion + * + * @param arrProperties array in: Properties wish list. + * @return integer Error stat + */ + public function Open($arrProperties) + { + global $dbmapping; + + // Create DSN String + $myDBDriver = $this->_logStreamConfigObj->GetPDODatabaseType(); + $myDsn = $this->_logStreamConfigObj->CreateConnectDSN(); + if ( strlen($myDsn) > 0 ) + { + // Check if configured driver is actually loaded! + //print_r(PDO::getAvailableDrivers()); + if ( !in_array($myDBDriver, PDO::getAvailableDrivers()) ) + { + $this->PrintDebugError('PDO Database Driver not loaded: ' . $myDBDriver . "
Please check your php configuration extensions"); + return ERROR_DB_INVALIDDBDRIVER; + } + + try + { + // Try to connect to the database + $this->_dbhandle = new PDO( $myDsn, $this->_logStreamConfigObj->DBUser, $this->_logStreamConfigObj->DBPassword); + +//$handle->setAttribute(PDO::ATTR_TIMEOUT, 3); + } + catch (PDOException $e) + { + $this->PrintDebugError('PDO Database Connection failed: ' . $e->getMessage() . "
DSN: " . $myDsn); + return ERROR_DB_CONNECTFAILED; + } + } + else + { + // Invalid DB Driver! + return ERROR_DB_INVALIDDBDRIVER; + } + + // Copy the Property Array + $this->_arrProperties = $arrProperties; + + // Check if DB Mapping exists + if ( !isset($dbmapping[ $this->_logStreamConfigObj->DBTableType ]) ) + return ERROR_DB_INVALIDDBMAPPING; + + // Create SQL Where Clause first! + $this->CreateSQLWhereClause(); + +// Success, this means we init the Pagenumber to ONE! +//$this->_currentPageNumber = 1; + + // reached this point means success! + return SUCCESS; + } + + /** + * Close the database connection. + * + * @return integer Error state + */ + public function Close() + { + if ( $this->_dbhandle != null ) + unset($this->_dbhandle); + return SUCCESS; + } + + /** + * Read the data from a specific uID which means in this + * case beginning with from the Database ID + * + * @param uID integer in/out: unique id of the data row + * @param arrProperitesOut array out: array filled with properties + * @return integer Error state + * @see ReadNext() + */ + public function Read($uID, &$arrProperitesOut) + { + // Seek the first uID! + if ( $this->Sseek($uID, EnumSeek::UID, 0) == SUCCESS) + { + // Read the next record! + $ret = $this->ReadNext($uID, $arrProperitesOut); + } + else + $ret = ERROR_NOMORERECORDS; + + // return result! + return $ret; + } + + /** + * Read the next line from the file depending on the current + * read direction. + * + * Hint: If the current stream becomes unavailable an error + * stated is retuned. A typical case is if a log rotation + * changed the original data source. + * + * @param uID integer out: uID is the offset of data row + * @param arrProperitesOut array out: properties + * @return integer Error state + * @see ReadNext + */ + public function ReadNext(&$uID, &$arrProperitesOut, $bParseMessage = true) + { + // Helpers needed for DB Mapping + global $dbmapping, $fields; + $szTableType = $this->_logStreamConfigObj->DBTableType; + + // define $ret + $ret = SUCCESS; + + // No buffer? then read from DB! + if ( $this->bufferedRecords == null ) + $ret = $this->ReadNextRecordsFromDB($uID); + else + { + if ( !isset($this->bufferedRecords[$this->_currentRecordNum] ) ) + { + // We need to load new records, so clear the old ones first! + $this->ResetBufferedRecords(); + + // Set new Record start, will be used in the SQL Statement! + $this->_currentRecordStart = $this->_currentRecordNum; // + 1; + + // Now read new ones + $ret = $this->ReadNextRecordsFromDB($uID); +echo "mowl2"; + + if ( !isset($this->bufferedRecords[$this->_currentRecordNum] ) ) + $ret = ERROR_NOMORERECORDS; + } + } + + if ( $ret == SUCCESS ) + { + // Init and set variables + foreach ( $this->_arrProperties as $property ) + { + // Check if mapping exists + if ( isset($dbmapping[$szTableType][$property]) ) + { + // Copy property if available! + $dbfieldname = $dbmapping[$szTableType][$property]; + if ( isset($this->bufferedRecords[$this->_currentRecordNum][$dbfieldname]) ) + { + if ( isset($fields[$property]['FieldType']) && $fields[$property]['FieldType'] == FILTER_TYPE_DATE ) // Handle as date! + $arrProperitesOut[$property] = GetEventTime( $this->bufferedRecords[$this->_currentRecordNum][$dbfieldname] ); + else + $arrProperitesOut[$property] = $this->bufferedRecords[$this->_currentRecordNum][$dbfieldname]; + } + else + $arrProperitesOut[$property] = ''; + } + else + $arrProperitesOut[$property] = ''; + } + + // Set uID to the PropertiesOut! //DEBUG -> $this->_currentRecordNum; + $uID = $arrProperitesOut[SYSLOG_UID] = $this->bufferedRecords[$this->_currentRecordNum][$dbmapping[$szTableType][SYSLOG_UID]]; + + // Increment $_currentRecordNum + $this->_currentRecordNum++; + } + + // reached here means return result! + return $ret; + } + + /** + * Implementation of Seek + */ + public function Sseek(&$uID, $mode, $numrecs) + { + // predefine return value + $ret = SUCCESS; + + switch ($mode) + { + case EnumSeek::UID: +// if ( $uID == UID_UNKNOWN ) // set uID to first ID! + { + // No buffer? then read from DB! + if ( $this->bufferedRecords == null ) + $ret = $this->ReadNextRecordsFromDB($uID); + + if ( $ret == SUCCESS ) + { + $this->_currentRecordNum = 0; + $uID = $this->bufferedRecords[ $this->_currentRecordNum ]; + } + } +/* else + { + // Obtain fieldname for uID + global $dbmapping; + $uidfieldname = $dbmapping[$this->_logStreamConfigObj->DBTableType][SYSLOG_UID]; + + // Clear if necessary! + if ( $this->bufferedRecords == null ) + $this->ResetBufferedRecords(); + + // Loop through all records for now, maybe optimized later! + $bFound = false; + $tmpuID = $uID; + $ret = ERROR_NOMORERECORDS; // Set Default error code! + + // Set totalpages number if available + if ( $this->_totalRecordCount != -1 ) + $totalpages = intval($this->_totalRecordCount / $this->_logStreamConfigObj->_pageCount); + else + $totalpages = 1; + + while( $bFound == false && $this->ReadNextIDsFromDB() == SUCCESS ) + { + foreach ( $this->bufferedRecords as $myRecord ) + { + if ( $myRecord[$uidfieldname] == $uID ) + { + $bFound = true; + $ret = SUCCESS; + break; // Break foreach loop! + } + else + { + $tmpuID = $myRecord[$uidfieldname]; + // Only Increment $_currentRecordNum + $this->_currentRecordNum++; + } + + // Increment our Pagenumber if needed! + if ( $this->_currentRecordNum % $this->_logStreamConfigObj->_pageCount == 0 ) + $this->_currentPageNumber++; + } + + if ( $this->_currentPageNumber > 1 && $this->_readDirection == EnumReadDirection::Forward) + $this->_currentPageNumber = $totalpages - $this->_currentPageNumber + 1; + + //--- Extra check to set the correct $_previousPageUID! + if ( $this->_currentRecordNum > $this->_logStreamConfigObj->_pageCount && isset($this->bufferedRecords[$this->_currentRecordNum - 50][$uidfieldname]) ) + { + $this->_previousPageUID = $this->bufferedRecords[$this->_currentRecordNum - $this->_logStreamConfigObj->_pageCount - 1][$uidfieldname]; + } + // TODO! Handle the case where previous ID is not set in the bufferedrecords! + //--- + + // We need to load new records, so clear the old ones first! + $this->ResetBufferedRecords(); + + // Set new Record start, will be used in the SQL Statement! + $this->_currentRecordStart = $this->_currentRecordNum; + } + + // Delete buffered records, then they will be read automatically in ReadNext() + $this->ResetBufferedRecords(); + } +*/ + break; + } + + // Return result! + return $ret; + } + + /** + * GetMessageCount will return the count of Message. + * If this count is not available, the function will + * return the default -1 + */ + public function GetMessageCount() + { + return $this->_totalRecordCount; + } + + /** + * This function returns the first UID for previous PAGE, if availbale! + * Otherwise will return -1! + */ + public function GetPreviousPageUID() + { + return $this->_previousPageUID; + } + + /** + * This function returns the first UID for the last PAGE! + * Will be done by a seperated SQL Statement. + */ + public function GetLastPageUID() + { + global $querycount, $dbmapping; + $szTableType = $this->_logStreamConfigObj->DBTableType; + + $szSql = "SELECT MIN(" . $dbmapping[$szTableType][SYSLOG_UID] . ") FROM " . $this->_logStreamConfigObj->DBTableName . $this->_SQLwhereClause; + $myQuery = $this->_dbhandle->query($szSql); + if ( $myQuery ) + { + $myRow = $myQuery->fetchColumn(); + $this->_lastPageUID = $myRow; // $myRow[0]; + + // Free query now + $myQuery->closeCursor(); + + // Increment for the Footer Stats + $querycount++; + + } +//echo $szSql . "
" . $this->_lastPageUID; +//exit; + + // finally return result! + return $this->_lastPageUID; + } + + /** + * This function returns the current Page number, if availbale! + * Otherwise will return 0! We also assume that this function is + * only called once DB is open! + */ + public function GetCurrentPageNumber() + { + return $this->_currentPageNumber; + } + + /* + * Implementation of IsPropertySortable + * + * For now, sorting is only possible for the UID Property! + */ + public function IsPropertySortable($myProperty) + { + global $fields; + + // TODO: HARDCODED | FOR NOW only FALSE! + return false; + + if ( isset($fields[$myProperty]) && $myProperty == SYSLOG_UID ) + return true; + else + return false; + } + + /* + * ============= Beginn of private functions ============= + */ + + /* + * This function expects the filters to already being set earlier. + * Otherwise no usual WHERE Clause can be created! + */ + private function CreateSQLWhereClause() + { + if ( $this->_filters != null ) + { + global $dbmapping; + $szTableType = $this->_logStreamConfigObj->DBTableType; + + // Reset WhereClause + $this->_SQLwhereClause = ""; + + // Loop through all available properties + foreach( $this->_arrProperties as $propertyname ) + { + // If the property exists in the filter array, we have something to filter for ^^! + if ( array_key_exists($propertyname, $this->_filters) ) + { + // Process all filters + foreach( $this->_filters[$propertyname] as $myfilter ) + { + switch( $myfilter[FILTER_TYPE] ) + { + case FILTER_TYPE_STRING: + // Check if user wants to include or exclude! + if ( $myfilter[FILTER_MODE] == FILTER_MODE_INCLUDE) + $addnod = ""; + else + $addnod = " NOT"; + + // If Syslog message, we have AND handling, otherwise OR! + if ( $propertyname == SYSLOG_MESSAGE ) + $addor = " AND "; + else + $addor = " OR "; + + // Not create LIKE Filters + if ( isset($tmpfilters[$propertyname]) ) + $tmpfilters[$propertyname][FILTER_VALUE] .= $addor . $dbmapping[$szTableType][$propertyname] . $addnod . " LIKE '%" . $myfilter[FILTER_VALUE] . "%'"; + else + { + $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_STRING; + $tmpfilters[$propertyname][FILTER_VALUE] = $dbmapping[$szTableType][$propertyname] . $addnod . " LIKE '%" . $myfilter[FILTER_VALUE] . "%'"; + } + break; + case FILTER_TYPE_NUMBER: + if ( isset($tmpfilters[$propertyname]) ) + $tmpfilters[$propertyname][FILTER_VALUE] .= ", " . $myfilter[FILTER_VALUE]; + else + { + $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_NUMBER; + $tmpfilters[$propertyname][FILTER_VALUE] = $dbmapping[$szTableType][$propertyname] . " IN (" . $myfilter[FILTER_VALUE]; + } + break; + case FILTER_TYPE_DATE: + if ( isset($tmpfilters[$propertyname]) ) + $tmpfilters[$propertyname][FILTER_VALUE] .= " AND "; + else + { + $tmpfilters[$propertyname][FILTER_VALUE] = ""; + $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_DATE; + } + + if ( $myfilter[FILTER_DATEMODE] == DATEMODE_LASTX ) + { + // Get current timestamp + $nNowTimeStamp = time(); + + if ( $myfilter[FILTER_VALUE] == DATE_LASTX_HOUR ) + $nNowTimeStamp -= 60 * 60; // One Hour! + else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_12HOURS ) + $nNowTimeStamp -= 60 * 60 * 12; // 12 Hours! + else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_24HOURS ) + $nNowTimeStamp -= 60 * 60 * 24; // 24 Hours! + else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_7DAYS ) + $nNowTimeStamp -= 60 * 60 * 24 * 7; // 7 days + else if ( $myfilter[FILTER_VALUE] == DATE_LASTX_31DAYS ) + $nNowTimeStamp -= 60 * 60 * 24 * 31; // 31 days + else + { + // Set filter to unknown and Abort in this case! + $tmpfilters[$propertyname][FILTER_TYPE] = FILTER_TYPE_UNKNOWN; + break; + } + + // Append filter + $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType][$propertyname] . " > '" . date("Y-m-d H:i:s", $nNowTimeStamp) . "'"; + } + else if ( $myfilter[FILTER_DATEMODE] == DATEMODE_RANGE_FROM ) + { + // Obtain Event struct for the time! + $myeventtime = GetEventTime($myfilter[FILTER_VALUE]); + $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType][$propertyname] . " > '" . date("Y-m-d H:i:s", $myeventtime[EVTIME_TIMESTAMP]) . "'"; + } + else if ( $myfilter[FILTER_DATEMODE] == DATEMODE_RANGE_TO ) + { + // Obtain Event struct for the time! + $myeventtime = GetEventTime($myfilter[FILTER_VALUE]); + $tmpfilters[$propertyname][FILTER_VALUE] .= $dbmapping[$szTableType][$propertyname] . " < '" . date("Y-m-d H:i:s", $myeventtime[EVTIME_TIMESTAMP]) . "'"; + } + + break; + default: + // Nothing to do! + break; + } + } + } + } + + // Check and combine all filters now! + if ( isset($tmpfilters) ) + { + // Append filters + foreach( $tmpfilters as $tmpfilter ) + { + // Init WHERE or Append AND + if ( strlen($this->_SQLwhereClause) > 0 ) + $this->_SQLwhereClause .= " AND "; + else + $this->_SQLwhereClause = " WHERE "; + + switch( $tmpfilter[FILTER_TYPE] ) + { + case FILTER_TYPE_STRING: + $this->_SQLwhereClause .= "( " . $tmpfilter[FILTER_VALUE] . ") "; + break; + case FILTER_TYPE_NUMBER: + $this->_SQLwhereClause .= $tmpfilter[FILTER_VALUE] . ") "; + break; + case FILTER_TYPE_DATE: + $this->_SQLwhereClause .= $tmpfilter[FILTER_VALUE]; + break; + default: + // Should not happen, wrong filters! + // We add a dummy into the where clause, just as a place holder + $this->_SQLwhereClause .= " 1=1 "; + break; + } + } + } + +//echo $this->_SQLwhereClause; + //$dbmapping[$szTableType][SYSLOG_UID] + } + else // No filters means nothing to do! + return SUCCESS; + } + + + /* + * This helper function will read the next records into the buffer. + */ + private function ReadNextRecordsFromDB($uID) + { + global $querycount; + + // Get SQL Statement + $szSql = $this->CreateSQLStatement($uID); + + // Append LIMIT clause +//$szSql .= " LIMIT " . $this->_currentRecordStart . ", " . $this->_logStreamConfigObj->RecordsPerQuery; + + // Perform Database Query + $myquery = $this->_dbhandle->query($szSql); + if ( !$myquery ) + { + $this->PrintDebugError("Invalid SQL: ".$szSql); + return ERROR_DB_QUERYFAILED; + } + + // Copy rows into the buffer! + $iBegin = $this->_currentRecordNum; + +// $result = $myquery->setFetchMode(PDO::FETCH_ASSOC); + + $iCount = 0; + while( $this->_logStreamConfigObj->RecordsPerQuery > $iCount ) + { + //Obtain next record + $myRow = $myquery->fetch(PDO::FETCH_ASSOC); +// if ( $iCount >= $this->_currentRecordStart ) +// { +// print_r( $iCount ); +// exit; + $this->bufferedRecords[$iBegin] = $myRow; + $iBegin++; +// } + + // Increment counter + $iCount++; + } +/* + foreach ($myquery as $myRow) + { + $this->bufferedRecords[$iBegin] = $myRow; + $iBegin++; + } +*/ + + // Free Query ressources +// $myquery->closeCursor(); + $myquery = null; + + + // Only obtain count if enabled and not done before + if ( $this->_logStreamConfigObj->DBEnableRowCounting && $this->_totalRecordCount == -1 ) + { + $this->_totalRecordCount = $this->GetRowCountFromTable(); + + if ( $this->_totalRecordCount <= 0 ) + return ERROR_NOMORERECORDS; + } + + // Increment for the Footer Stats + $querycount++; + + // return success state if reached this point! + return SUCCESS; + } + + /* + * Creates the SQL Statement we are going to use! + */ + private function CreateSQLStatement($uID, $includeFields = true) + { + global $dbmapping; + + // Copy helper variables, this is just for better readability + $szTableType = $this->_logStreamConfigObj->DBTableType; + $szSortColumn = $this->_logStreamConfigObj->SortColumn; + + // Create Basic SQL String +// if ( $this->_logStreamConfigObj->DBEnableRowCounting ) // with SQL_CALC_FOUND_ROWS +// $sqlString = "SELECT SQL_CALC_FOUND_ROWS " . $dbmapping[$szTableType][SYSLOG_UID]; +// else // without row calc + $sqlString = "SELECT " . $dbmapping[$szTableType][SYSLOG_UID]; + + // Append fields if needed + if ( $includeFields && $this->_arrProperties != null ) + { + // Loop through all requested fields + foreach ( $this->_arrProperties as $myproperty ) + { + // SYSLOG_UID already added! + if ( $myproperty != SYSLOG_UID && isset($dbmapping[$szTableType][$myproperty]) ) + { + // Append field! + $sqlString .= ", " . $dbmapping[$szTableType][$myproperty]; + } + } + } + + // Append FROM 'table'! + $sqlString .= " FROM " . $this->_logStreamConfigObj->DBTableName; + + // Append precreated where clause + $sqlString .= $this->_SQLwhereClause; + + // Append UID QUERY! + if ( $uID != -1 ) + { + if ( $this->_readDirection == EnumReadDirection::Forward ) + $myOperator = ">="; + else + $myOperator = "<="; + + if ( strlen($this->_SQLwhereClause) > 0 ) + $sqlString .= " AND " . $dbmapping[$szTableType][SYSLOG_UID] . " $myOperator $uID"; + else + $sqlString .= " WHERE " . $dbmapping[$szTableType][SYSLOG_UID] . " $myOperator $uID"; + } + + // Append ORDER clause + if ( $this->_readDirection == EnumReadDirection::Forward ) + $sqlString .= " ORDER BY " . $dbmapping[$szTableType][$szSortColumn]; + else if ( $this->_readDirection == EnumReadDirection::Backward ) + $sqlString .= " ORDER BY " . $dbmapping[$szTableType][$szSortColumn] . " DESC"; + +//echo $sqlString; +//exit; + + // return SQL result string: + return $sqlString; + } + + /* + * Reset record buffer in this function! + */ + private function ResetBufferedRecords() + { + if ( isset($this->bufferedRecords) ) + { + // Loop through all subrecords first! + foreach ($this->bufferedRecords as $mykey => $myrecord) + unset( $this->bufferedRecords[$mykey] ); + + // Set buffered records to NULL! + $this->bufferedRecords = null; + } + } + + /* + * Helper function to display SQL Errors for now! + */ + private function PrintDebugError($szErrorMsg) + { + global $CFG; + if ( isset($CFG['MiscShowDebugMsg']) && $CFG['MiscShowDebugMsg'] == 1 ) + { + $errdesc = $this->_dbhandle == null ? "" : implode( ";", $this->_dbhandle->errorInfo() ); + $errno = $this->_dbhandle == null ? "" : $this->_dbhandle->errorCode(); + + $errormsg ="
"; + $errormsg.="

Error: " . $szErrorMsg . "


"; + $errormsg.="Errordetails:
"; + $errormsg.="Detail Error: $errdesc
"; + $errormsg.="Error Code: $errno
"; + $errormsg.="Date: ".date("d.m.Y @ H:i"). "
"; + $errormsg.="
"; + + //Output! + print( $errormsg ); + } + } + + /* + * Returns the number of possible records by using a select count statement! + */ + private function GetRowCountFromTable() + { +/* + if ( $myquery = mysql_query("Select FOUND_ROWS();", $this->_dbhandle) ) + { + // Get first and only row! + $myRow = mysql_fetch_array($myquery); + + // copy row count + $numRows = $myRow[0]; + } + else + $numRows = -1; +*/ + + /* OLD slow code! */ + global $dbmapping,$querycount; + $szTableType = $this->_logStreamConfigObj->DBTableType; + + // Create Statement and perform query! + $szSql = "SELECT count(" . $dbmapping[$szTableType][SYSLOG_UID] . ") FROM " . $this->_logStreamConfigObj->DBTableName . $this->_SQLwhereClause; + $myQuery = $this->_dbhandle->query($szSql); + if ($myQuery) + { + // obtain first and only row + $myRow = $myQuery->fetchColumn(); + $numRows = $myRow; // $myRow[0]; + + // Increment for the Footer Stats + $querycount++; + + // Free query now + $myQuery->closeCursor(); + } + else + $numRows = -1; + + // return result! + return $numRows; + } + + +} + +?> \ No newline at end of file diff --git a/src/include/constants_errors.php b/src/include/constants_errors.php index 7f63664..6ca7855 100644 --- a/src/include/constants_errors.php +++ b/src/include/constants_errors.php @@ -55,7 +55,9 @@ define('ERROR_DB_CANNOTSELECTDB', 11); define('ERROR_DB_QUERYFAILED', 12); define('ERROR_DB_NOPROPERTIES', 13); define('ERROR_DB_INVALIDDBMAPPING', 14); +define('ERROR_DB_INVALIDDBDRIVER', 16); define('ERROR_FILE_NOT_READABLE', 15); + ?> diff --git a/src/include/constants_general.php b/src/include/constants_general.php index eb545f2..f0c737f 100644 --- a/src/include/constants_general.php +++ b/src/include/constants_general.php @@ -60,6 +60,7 @@ define('STR_DEBUG_ERROR_WTF', "WTF OMFG"); // --- Source Type defines define('SOURCE_DISK', '1'); define('SOURCE_DB', '2'); +define('SOURCE_PDO', '3'); // --- // --- diff --git a/src/include/constants_logstream.php b/src/include/constants_logstream.php index 55dfd24..f4056bd 100644 --- a/src/include/constants_logstream.php +++ b/src/include/constants_logstream.php @@ -70,6 +70,11 @@ define('FILTER_TYPE_UNKNOWN', 99); define('DB_MYSQL', 0); define('DB_MSSQL', 1); define('DB_ODBC', 2); +define('DB_PGSQL', 3); +define('DB_OCI', 4); +define('DB_DB2', 5); +define('DB_FIREBIRD', 6); +define('DB_INFORMIX', 7); // --- Predefine fields array! $fields[SYSLOG_UID]['FieldID'] = SYSLOG_UID; diff --git a/src/include/functions_config.php b/src/include/functions_config.php index d37b7a6..b55a387 100644 --- a/src/include/functions_config.php +++ b/src/include/functions_config.php @@ -100,6 +100,24 @@ if ( isset($mysource['DBPassword']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBPassword = $mysource['DBPassword']; } if ( isset($mysource['DBEnableRowCounting']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBEnableRowCounting = $mysource['DBEnableRowCounting']; } } + else if ( $mysource['SourceType'] == SOURCE_PDO ) + { + // Perform necessary include + require_once($gl_root_path . 'classes/logstreamconfigpdo.class.php'); + + $content['Sources'][$iSourceID]['ObjRef'] = new LogStreamConfigPDO(); + $content['Sources'][$iSourceID]['ObjRef']->DBServer = $mysource['DBServer']; + $content['Sources'][$iSourceID]['ObjRef']->DBName = $mysource['DBName']; + $content['Sources'][$iSourceID]['ObjRef']->DBType = $mysource['DBType']; + $content['Sources'][$iSourceID]['ObjRef']->DBTableName = $mysource['DBTableName']; + $content['Sources'][$iSourceID]['ObjRef']->DBTableType = strtolower($mysource['DBTableType']); + + // Optional parameters! + if ( isset($mysource['DBPort']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBPort = $mysource['DBPort']; } + if ( isset($mysource['DBUser']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBUser = $mysource['DBUser']; } + if ( isset($mysource['DBPassword']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBPassword = $mysource['DBPassword']; } + if ( isset($mysource['DBEnableRowCounting']) ) { $content['Sources'][$iSourceID]['ObjRef']->DBEnableRowCounting = $mysource['DBEnableRowCounting']; } + } else { // UNKNOWN, remove config entry! diff --git a/src/index.php b/src/index.php index db450e9..361e05a 100644 --- a/src/index.php +++ b/src/index.php @@ -231,7 +231,7 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c // Set current ID and init Counter $uID = $content['uid_current']; $counter = 0; - + // If uID is known, we need to init READ first - this will also seek for available records first! if ($uID != UID_UNKNOWN) { @@ -244,6 +244,7 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c // --- Check if Read was successfull! if ( $ret == SUCCESS ) { +/* OLD CODE // If Forward direction is used, we need to SKIP one entry! if ( $content['read_direction'] == EnumReadDirection::Forward ) { @@ -253,6 +254,7 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c // Skip this entry and move to the next $stream->ReadNext($uID, $logArray); } +*/ } else { @@ -578,16 +580,8 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c else if ( $content['uid_current'] != UID_UNKNOWN ) $content['main_pager_next_found'] = false; } - else if ( $content['read_direction'] == EnumReadDirection::Forward ) - { - // User clicked back, so there is a next page for sure - $content['main_pager_next_found'] = true; - - // As we went back, we need to change the currend uid to the latest read one - $content['uid_current'] = $uID; - } // --- - + // --- Handle uid_previous page button if ( $content['uid_current'] != UID_UNKNOWN ) { @@ -616,13 +610,27 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c // --- Handle uid_last page button // Option the last UID from the stream! $content['uid_last'] = $stream->GetLastPageUID(); - + // if we found a last uid, and if it is not the current one (which means we already are on the last page ;)! if ( $content['uid_last'] != -1 && $content['uid_last'] != $content['uid_current']) $content['main_pager_last_found'] = true; else $content['main_pager_last_found'] = false; //echo $content['uid_last']; + + // Handle next button only if Forward is used now! + if ( $content['read_direction'] == EnumReadDirection::Forward ) + { + if ( $content['uid_current'] == $content['uid_last'] ) + // Last page already ! + $content['main_pager_next_found'] = false; + else + // User clicked back, so there is a next page for sure + $content['main_pager_next_found'] = true; + + // As we went back, we need to change the currend uid to the latest read one + $content['uid_current'] = $uID; + } // --- // --- Handle uid_first page button @@ -657,7 +665,7 @@ if ( isset($content['Sources'][$currentSourceID]) ) // && $content['Sources'][$c else if ( $res == ERROR_FILE_NOT_READABLE ) $content['detailederror'] = "Syslog file is not readable, read access may be denied. "; else - $content['detailederror'] = "Unknown or unhandeled error occured."; + $content['detailederror'] = "Unknown or unhandeled error occured (Error Code " . $res . ") "; } diff --git a/src/templates/index.html b/src/templates/index.html index 38f9a02..997543a 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -181,7 +181,7 @@ - + @@ -328,7 +328,7 @@ - +