mirror of
https://github.com/rsyslog/loganalyzer.git
synced 2025-09-26 11:19:26 +02:00
753 lines
19 KiB
PHP
753 lines
19 KiB
PHP
<?php
|
|
/*
|
|
*********************************************************************
|
|
* -> www.phplogcon.org <- *
|
|
* ----------------------------------------------------------------- *
|
|
* Some constants *
|
|
* *
|
|
* LogStreamDisk provides access to the data on disk. In the most
|
|
* cases this will be plain text files. If we need access to e.g.
|
|
* zipped files, this will be handled by a separate driver.
|
|
*
|
|
* \version 2.0.1 2nd Version
|
|
* \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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* 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 LogStreamDisk extends LogStream {
|
|
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;
|
|
|
|
private $_previousPageUID = -1;
|
|
private $_lastPageUID = -1;
|
|
|
|
// Constructor
|
|
public function LogStreamDisk($streamConfigObj) {
|
|
$this->_logStreamConfigObj = $streamConfigObj;
|
|
}
|
|
|
|
/**
|
|
* Open the file with read access.
|
|
*
|
|
* @param arrProperties array in: Properties wish list.
|
|
* @return integer Error stat
|
|
*/
|
|
public function Open($arrProperties)
|
|
{
|
|
// Initialise Basic stuff within the Classs
|
|
$this->RunBasicInits();
|
|
|
|
// Check if file exists!
|
|
$result = $this->Verify();
|
|
if ( $result != SUCCESS)
|
|
return $result;
|
|
|
|
// Now open the file
|
|
$this->_fp = fopen($this->_logStreamConfigObj->FileName, 'r');
|
|
$this->_currentOffset = ftell($this->_fp);
|
|
$this->_currentStartPos = $this->_currentOffset;
|
|
$this->_arrProperties = $arrProperties;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Close the file.
|
|
*
|
|
* @return integer Error state
|
|
*/
|
|
public function Close() {
|
|
|
|
if ( isset($this->_fp) )
|
|
{
|
|
if (!fclose($this->_fp)) {
|
|
return ERROR_FILE_CANT_CLOSE;
|
|
}
|
|
}
|
|
|
|
// return result
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Verify if the file exists!
|
|
*
|
|
* @return integer Error state
|
|
*/
|
|
public function Verify() {
|
|
|
|
// Check if file exists!
|
|
if(!file_exists($this->_logStreamConfigObj->FileName)) {
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
// Check if file is readable!
|
|
if(!is_readable($this->_logStreamConfigObj->FileName)) {
|
|
return ERROR_FILE_NOT_READABLE;
|
|
}
|
|
|
|
// reached this point means success ;)!
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
private function ReadNextBlock() {
|
|
$this->_bEOS = false;
|
|
$bCheckForLastLf = false;
|
|
|
|
if ($this->_readDirection == EnumReadDirection::Backward) {
|
|
// in this case we have to adjust a few settings
|
|
$this->_p_buffer = self::_BUFFER_length ; // set the point to the right index
|
|
|
|
// first of all, check if this is the first read
|
|
if ($this->_buffer == false) {
|
|
// this means that we have to read from the end
|
|
fseek($this->_fp, 0, SEEK_END);
|
|
$this->_currentOffset = ftell($this->_fp);
|
|
$this->_p_buffer -= 1; // eat EOF
|
|
$bCheckForLastLf = true;
|
|
}
|
|
|
|
$orig_offset = ftell($this->_fp) - $this->_buffer_length;
|
|
|
|
if ($orig_offset <= 0) {
|
|
// apparently we are at BOF so nothing to read
|
|
return ERROR_EOS;
|
|
}
|
|
|
|
// jumb to the new position
|
|
$orig_offset -= self::_BUFFER_length;
|
|
if ($orig_offset <= 0) {
|
|
// ok, we have to adjust the buffer pointer
|
|
$this->_p_buffer += $orig_offset; // note orig_offset is negative, see if
|
|
$orig_offset = 0;
|
|
}
|
|
fseek($this->_fp, $orig_offset);
|
|
|
|
} else {
|
|
$this->_p_buffer = 0;
|
|
}
|
|
|
|
$this->_buffer = fread($this->_fp, self::_BUFFER_length);
|
|
$this->_buffer_length = strlen($this->_buffer);
|
|
|
|
if ($bCheckForLastLf && $this->_buffer[$this->_p_buffer] == "\n") {
|
|
// skip it (can only occur if you read backwards)
|
|
$this->_p_buffer--;
|
|
$this->_currentOffset--;
|
|
}
|
|
|
|
if ($this->_buffer == false)
|
|
return ERROR_FILE_EOF;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Read the data from a specific uID which means in this
|
|
* case from a given offset of the file.
|
|
*
|
|
* @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) {
|
|
$this->Sseek($uID, EnumSeek::UID, 0);
|
|
$tmp = $this->_readDirection;
|
|
$this->_readDirection = EnumReadDirection::Forward;
|
|
$ret = $this->ReadNext($uID, $arrProperitesOut);
|
|
if ($tmp == EnumReadDirection::Backward) {
|
|
|
|
$this->_p_buffer -= 2;
|
|
$this->_currentStartPos = $this->_currentOffset -= 1;
|
|
|
|
$this->_readDirection = $tmp;
|
|
// we have to skip one line that we are back on the right position
|
|
$this->ReadNext($dummy1, $dummy2);
|
|
}
|
|
|
|
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)
|
|
{
|
|
global $content, $gl_starttime;
|
|
|
|
do
|
|
{
|
|
// Read next entry first!
|
|
if ($this->_readDirection == EnumReadDirection::Forward)
|
|
$ret = $this->ReadNextForwards($uID, $arrProperitesOut);
|
|
else
|
|
$ret = $this->ReadNextBackwards($uID, $arrProperitesOut);
|
|
|
|
// Only PARSE on success!
|
|
if ( $ret == SUCCESS && $bParseMessage)
|
|
{
|
|
// Line Parser Hook here
|
|
$retParser = $this->_logStreamConfigObj->_lineParser->ParseLine($arrProperitesOut[SYSLOG_MESSAGE], $arrProperitesOut);
|
|
|
|
// Run optional Message Parsers now
|
|
$retParser = $this->_logStreamConfigObj->ProcessMsgParsers($arrProperitesOut[SYSLOG_MESSAGE], $arrProperitesOut);
|
|
|
|
// Check if we have to skip the message!
|
|
if ( $retParser == ERROR_MSG_SKIPMESSAGE )
|
|
$ret = $retParser;
|
|
|
|
// Set uID to the PropertiesOut!
|
|
$arrProperitesOut[SYSLOG_UID] = $uID;
|
|
}
|
|
|
|
// Check how long we are running. If only two seconds of execution time are left, we abort further reading!
|
|
$scriptruntime = intval(microtime_float() - $gl_starttime);
|
|
if ( $scriptruntime > ($content['MaxExecutionTime']-2) )
|
|
{
|
|
// This may display a warning message, so the user knows we stopped reading records because of the script timeout.
|
|
$content['logstream_warning'] = "false";
|
|
$content['logstream_warning_details'] = $content['LN_WARNING_LOGSTREAMDISK_TIMEOUT'];
|
|
$content['logstream_warning_code'] = ERROR_FILE_NOMORETIME;
|
|
|
|
// Return error code
|
|
return ERROR_FILE_NOMORETIME;
|
|
}
|
|
|
|
// Loop until the filter applies, or another error occurs, and we still have TIME!
|
|
} while ( $this->ApplyFilters($ret, $arrProperitesOut) != SUCCESS && $ret == SUCCESS );
|
|
|
|
// reached here means return result!
|
|
return $ret;
|
|
}
|
|
|
|
private function ReadNextForwards(&$uID, &$arrProperitesOut) {
|
|
if ($this->_bEOS) {
|
|
return ERROR_EOS;
|
|
}
|
|
|
|
if ($this->_p_buffer < 0) {
|
|
// init read
|
|
$this->ReadNextBlock();
|
|
}
|
|
|
|
if (($this->_p_buffer == $this->_buffer_length || $this->_p_buffer == -1) && ($this->ReadNextBlock() != SUCCESS)) {
|
|
return ERROR_UNDEFINED;
|
|
}
|
|
|
|
// Init variables dynamically
|
|
$line = '';
|
|
if ( $this->_arrProperties != null )
|
|
{
|
|
foreach ( $this->_arrProperties as $property )
|
|
$arrProperitesOut[$property] = '';
|
|
}
|
|
|
|
do {
|
|
$pos = -1;
|
|
if (($pos = strpos($this->_buffer, "\n", $this->_p_buffer)) !== false) {
|
|
$uID = $this->_currentStartPos;
|
|
$logLine = $line . substr($this->_buffer, $this->_p_buffer, $pos - $this->_p_buffer);
|
|
$arrProperitesOut[SYSLOG_MESSAGE] = $logLine;
|
|
|
|
// the buffer pointer currently points to the linefeed
|
|
// so we have to increment the pointer to eat it
|
|
$this->_currentOffset += $pos - $this->_p_buffer + 1;
|
|
$this->_p_buffer = $pos + 1;
|
|
$this->_currentStartPos = $this->_currentOffset;
|
|
return SUCCESS;
|
|
}
|
|
|
|
$line .= substr($this->_buffer, $this->_p_buffer, $this->_buffer_length - $this->_p_buffer);
|
|
$this->_currentOffset += $this->_buffer_length - $this->_p_buffer;
|
|
} while ($this->ReadNextBlock() == SUCCESS);
|
|
|
|
if ( strlen($line) > 0 ) {
|
|
$uID = $this->_currentStartPos;
|
|
$arrProperitesOut[SYSLOG_MESSAGE] = $line;
|
|
|
|
$this->_currentStartPos = $this->_currentOffset;
|
|
return SUCCESS;
|
|
}
|
|
return ERROR_UNDEFINED;
|
|
}
|
|
|
|
private function ReadNextBackwards(&$uID, &$arrProperitesOut) {
|
|
if ($this->_bEOS) {
|
|
return ERROR_EOS;
|
|
}
|
|
|
|
if ($this->_p_buffer < 0) {
|
|
// a negative buffer means that the we have to adjust
|
|
// the offset
|
|
$this->_currentOffset++;
|
|
if ($this->ReadNextBlock() != SUCCESS) {
|
|
return ERROR_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
// Init variables dynamically
|
|
$line = '';
|
|
foreach ( $this->_arrProperties as $property )
|
|
$arrProperitesOut[$property] = '';
|
|
|
|
do {
|
|
$pos = -1;
|
|
$neg_offset = ($this->_buffer_length - $this->_p_buffer) * -1;
|
|
if (($pos = strrpos($this->_buffer, "\n", $neg_offset)) !== false) {
|
|
// note that we are at the position of the linefeed,
|
|
// this is recognize in the next few calculation
|
|
$uID = $this->_currentOffset -= $this->_p_buffer - $pos;
|
|
$arrProperitesOut[SYSLOG_MESSAGE] = substr($this->_buffer, $pos + 1, $this->_p_buffer - $pos) . $line;
|
|
|
|
$this->_currentOffset--; // eat the lf
|
|
$this->_p_buffer = $pos - 1;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
$line = substr($this->_buffer, 0, $this->_p_buffer) . $line;
|
|
$this->_currentOffset -= $this->_p_buffer;
|
|
|
|
} while ($this->ReadNextBlock() == SUCCESS);
|
|
|
|
if ( strlen($line) > 0 ) {
|
|
// this case should only happend if we are on BOF
|
|
$this->_bEOS = true;
|
|
|
|
$uID = 0;
|
|
$arrProperitesOut[SYSLOG_MESSAGE] = $line;
|
|
|
|
return SUCCESS;
|
|
}
|
|
return ERROR_EOS;
|
|
}
|
|
|
|
/**
|
|
* Implementation of Seek
|
|
*/
|
|
public function Sseek(&$uID, $mode, $numrecs) {
|
|
// in any case we reset the buffer
|
|
$this->ResetBuffer();
|
|
|
|
$ret = -1;
|
|
|
|
switch ($mode) {
|
|
case EnumSeek::BOS:
|
|
$ret = fseek($this->_fp, 0);
|
|
$this->_currentOffset = $this->_currentStartPos = 0;
|
|
break;
|
|
case EnumSeek::EOS:
|
|
// a simple ReadNextBackup will do all the work
|
|
// for us, because we have reset the buffer
|
|
// remember the current readDirection
|
|
|
|
$tmp = $this->_readDirection;
|
|
$this->_readDirection = EnumReadDirection::Backward;
|
|
$ret = $this->ReadNextBackwards($uID, $dummy2);
|
|
if ($tmp == EnumReadDirection::Forward) {
|
|
// in this case we have to correct the buffer,
|
|
// because we have read backwards even the current
|
|
// readDirection is forwards
|
|
$this->_p_buffer += 2;
|
|
$this->_currentStartPos = $this->_currentOffset;
|
|
}
|
|
$this->_readDirection = $tmp;
|
|
break;
|
|
case EnumSeek::UID:
|
|
$ret = fseek($this->_fp, $uID);
|
|
$this->_currentOffset = $this->_currentStartPos = $uID;
|
|
break;
|
|
}
|
|
|
|
if ($ret != SUCCESS)
|
|
return ERROR_UNDEFINED;
|
|
|
|
return $this->Skip($uID, $numrecs);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param numrecs integer in: If positiv, skip
|
|
* @return uid integer Error state
|
|
*/
|
|
private function Skip($uID, $numrecs) {
|
|
if ($numrecs == 0)
|
|
return SUCCESS;
|
|
|
|
if ($numrecs > 0) {
|
|
/* due to performance reason we use php's fgets instead of ReadNext method
|
|
while (!feof($this->_fp)) {
|
|
fgets($this->_fp);
|
|
$numrecs--;
|
|
if ($numrecs == 0) {
|
|
break;
|
|
}
|
|
$this->_currentOffset = ftell($this->_fp);
|
|
}
|
|
*/
|
|
while ($this->ReadNextForwards($dummy1, $dummy2) == SUCCESS)
|
|
{
|
|
fgets($this->_fp);
|
|
$numrecs--;
|
|
|
|
//--- Extra check to set the correct $_previousPageUID!
|
|
if ( $numrecs == $this->_logStreamConfigObj->_pageCount )
|
|
$this->_previousPageUID = $this->_currentOffset;
|
|
//---
|
|
|
|
if ($numrecs == 0) {
|
|
break;
|
|
}
|
|
$this->_currentOffset = ftell($this->_fp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ($this->ReadNextBackwards($dummy1, $dummy2) == SUCCESS)
|
|
{
|
|
$numrecs++;
|
|
|
|
//--- Extra check to set the correct $_previousPageUID!
|
|
if ( $numrecs == $this->_logStreamConfigObj->_pageCount )
|
|
$this->_previousPageUID = $this->_currentOffset;
|
|
//---
|
|
|
|
if ($numrecs == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// where we are?
|
|
$uID = $this->_currentOffset;
|
|
|
|
if ($numrecs != 0) {
|
|
// obviously there were not enough records to skip
|
|
return ERROR_NOMORERECORDS;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the filter for the current stream.
|
|
*
|
|
* @param filter object in: filter object
|
|
* @return integer Error state
|
|
public function SetFilter($filter) {
|
|
return SUCCESS;
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* GetMessageCount will always return -1 which means
|
|
* that the message count is not available. We refuse
|
|
* the request of the message count due to a count would
|
|
* require to read the whole file which would be a big
|
|
* pain if the file is e.g. 1 gb.
|
|
*/
|
|
public function GetMessageCount() {
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* 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 FIRST PAGE!
|
|
* NOT IMPLEMENTED RIGHT NOW!
|
|
*/
|
|
public function GetFirstPageUID()
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* This function returns the first UID for the last PAGE!
|
|
* This is not possible in this logstream, so it always returns -1!
|
|
*/
|
|
public function GetLastPageUID()
|
|
{
|
|
// Only perform lastUID scan if there are NO filters, for performance REASONS!
|
|
if ( $this->_filters != null )
|
|
return UID_UNKNOWN;
|
|
|
|
// Helper variables
|
|
$myuid = -1;
|
|
$counter = 0;
|
|
$tmpOldDirection = $this->_readDirection; // Store for later use
|
|
$tmpuID = $this->_currentOffset+1; // Store for later use
|
|
$tmpArray = array();
|
|
|
|
if ( $this->_sortOrder == EnumSortingOrder::Ascending )
|
|
{
|
|
// Move to the beginning of END file!
|
|
$this->Sseek($myuid, EnumSeek::EOS, 0);
|
|
|
|
// Switch reading direction!
|
|
$this->_readDirection = EnumReadDirection::Backward;
|
|
}
|
|
else if ( $this->_sortOrder == EnumSortingOrder::Descending )
|
|
{
|
|
// Move to the beginning of the file!
|
|
$this->Sseek($myuid, EnumSeek::BOS, 0);
|
|
|
|
// Switch reading direction!
|
|
$this->_readDirection = EnumReadDirection::Forward;
|
|
}
|
|
|
|
// Now we move for one page, we do not need to process the syslog messages!
|
|
$ret = $this->ReadNext($myuid, $tmpArray, false);
|
|
|
|
// Save the current UID as LastPage UID!
|
|
$this->_lastPageUID = $myuid;
|
|
|
|
// --- Restore reading direction and file position!
|
|
$this->_readDirection = $tmpOldDirection;
|
|
$ret = $this->Read($tmpuID, $tmpArray);
|
|
|
|
// if ( $this->_readDirection == EnumReadDirection::Forward )
|
|
// $this->Sseek($myuid, EnumSeek::BOS, 0);
|
|
// else
|
|
// $this->Sseek($myuid, EnumSeek::EOS, 0);
|
|
// ---
|
|
|
|
// Return result!
|
|
return $this->_lastPageUID;
|
|
}
|
|
|
|
/**
|
|
* This function returns the current Page number, if availbale!
|
|
* Otherwise will return -1!
|
|
*/
|
|
public function GetCurrentPageNumber()
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Implementation of GetLogStreamStats
|
|
*
|
|
* Returns an Array og logstream statsdata
|
|
* Count of Data Items
|
|
* Total Filesize
|
|
*/
|
|
public function GetLogStreamStats()
|
|
{
|
|
// Get some file data!
|
|
|
|
/*
|
|
// return results!
|
|
return $stats;
|
|
}
|
|
else
|
|
*/
|
|
// NOT IMPLEMENTED YET!
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Implementation of GetLogStreamTotalRowCount
|
|
*
|
|
* not implemented yet!
|
|
*/
|
|
public function GetLogStreamTotalRowCount()
|
|
{
|
|
//not implemented
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Implementation of the CleanupLogdataByDate
|
|
*
|
|
* not implemented yet!
|
|
*/
|
|
public function CleanupLogdataByDate( $nDateTimeStamp )
|
|
{
|
|
//not implemented
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Implementation of GetCountSortedByField
|
|
*
|
|
* For now, the disk source needs to loop through the whole file
|
|
* to consolidate and sort the data
|
|
*
|
|
* @return integer Error stat
|
|
*/
|
|
public function GetCountSortedByField($szFieldId, $nFieldType, $nRecordLimit)
|
|
{
|
|
global $content;
|
|
|
|
// We loop through all loglines! this may take a while!
|
|
$uID = UID_UNKNOWN;
|
|
$ret = $this->ReadNext($uID, $logArray);
|
|
if ( $ret == SUCCESS )
|
|
{
|
|
// Initialize Array variable
|
|
$aResult = array();
|
|
|
|
// Loop through messages
|
|
do
|
|
{
|
|
if ( isset($logArray[$szFieldId]) )
|
|
{
|
|
if ( $nFieldType == FILTER_TYPE_DATE )
|
|
{
|
|
// Convert to FULL Day Date for now!
|
|
$myFieldData = date( "Y-m-d", $logArray[$szFieldId][EVTIME_TIMESTAMP] );
|
|
}
|
|
else // Just copy the value!
|
|
$myFieldData = $logArray[$szFieldId];
|
|
|
|
if ( isset($aResult[ $myFieldData ]) )
|
|
$aResult[ $myFieldData ]++;
|
|
else
|
|
{
|
|
// Initialize entry if we haven't exceeded the RecordLImit yet!
|
|
if ( count($aResult) < ($nRecordLimit-1) ) // -1 because the last entry will become all others
|
|
$aResult[ $myFieldData ] = 1;
|
|
else
|
|
{
|
|
// Count record to others
|
|
if ( isset($aResult[ $content['LN_STATS_OTHERS'] ]) )
|
|
$aResult[ $content['LN_STATS_OTHERS'] ]++;
|
|
else
|
|
$aResult[ $content['LN_STATS_OTHERS'] ] = 1;
|
|
}
|
|
}
|
|
}
|
|
} while ( ($ret = $this->ReadNext($uID, $logArray)) == SUCCESS );
|
|
|
|
// Sort Array, so the highest count comes first!
|
|
arsort($aResult);
|
|
// array_multisort($aResult, SORT_NUMERIC, SORT_DESC);
|
|
|
|
if ( isset($aResult[ $content['LN_STATS_OTHERS'] ]) )
|
|
{
|
|
// This will move the "Others" Element to the last position!
|
|
$arrEntryCopy = $aResult[ $content['LN_STATS_OTHERS'] ];
|
|
unset($aResult[ $content['LN_STATS_OTHERS'] ]);
|
|
$aResult[ $content['LN_STATS_OTHERS'] ] = $arrEntryCopy;
|
|
}
|
|
|
|
// finally return result!
|
|
if ( count($aResult) > 0 )
|
|
return $aResult;
|
|
else
|
|
return ERROR_NOMORERECORDS;
|
|
}
|
|
else
|
|
return ERROR_NOMORERECORDS;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the direction the stream should read data.
|
|
*
|
|
*
|
|
*
|
|
* @param enumReadDirectionfilter EnumReadDirection in: The new direction.
|
|
* @return integer Error state
|
|
*
|
|
public function SetReadDirection($enumReadDirection) {
|
|
|
|
// only if the read direction change we have do do anything
|
|
if ($this->_readDirection == $enumReadDirection)
|
|
return SUCCESS;
|
|
|
|
$this->_readDirection = $enumReadDirection;
|
|
return SUCCESS;
|
|
}
|
|
*/
|
|
|
|
private function ResetBuffer() {
|
|
$this->_bEOS = false;
|
|
$this->_buffer = false;
|
|
$this->_buffer_length = 0;
|
|
$this->_p_buffer = -1;
|
|
}
|
|
|
|
}
|
|
?>
|