2011-06-21 17:19:10 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
switch ( $_REQUEST['task'] )
|
|
|
|
{
|
|
|
|
case 'create' :
|
|
|
|
{
|
2011-08-26 18:50:50 +08:00
|
|
|
// Silently ignore bogus requests
|
|
|
|
if ( !empty($_POST['level']) && !empty($_POST['message']) )
|
|
|
|
{
|
|
|
|
logInit( array( 'id' => "web_js" ) );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2011-08-26 18:50:50 +08:00
|
|
|
$string = $_POST['message'];
|
2014-11-13 22:17:54 +08:00
|
|
|
|
|
|
|
$file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : '';
|
2011-08-26 18:50:50 +08:00
|
|
|
if ( !empty( $_POST['line'] ) )
|
|
|
|
$line = $_POST['line'];
|
|
|
|
else
|
|
|
|
$line = NULL;
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2011-08-26 18:50:50 +08:00
|
|
|
$levels = array_flip(Logger::$codes);
|
|
|
|
if ( !isset($levels[$_POST['level']]) )
|
|
|
|
Panic( "Unexpected logger level '".$_POST['level']."'" );
|
|
|
|
$level = $levels[$_POST['level']];
|
|
|
|
Logger::fetch()->logPrint( $level, $string, $file, $line );
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
ajaxResponse();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'query' :
|
|
|
|
{
|
|
|
|
if ( !canView( 'System' ) )
|
|
|
|
ajaxError( 'Insufficient permissions to view log entries' );
|
|
|
|
|
2011-08-26 18:50:50 +08:00
|
|
|
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
|
|
|
|
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
|
2013-11-13 23:11:16 +08:00
|
|
|
$limit = isset($_POST['limit'])?$_POST['limit']:100;
|
2011-08-26 18:50:50 +08:00
|
|
|
$filter = isset($_POST['filter'])?$_POST['filter']:array();
|
|
|
|
$sortField = isset($_POST['sortField'])?$_POST['sortField']:'TimeKey';
|
2014-06-29 20:09:59 +08:00
|
|
|
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc';
|
2011-06-21 17:19:10 +08:00
|
|
|
|
|
|
|
$filterFields = array( 'Component', 'Pid', 'Level', 'File', 'Line' );
|
|
|
|
|
2014-09-27 02:43:58 +08:00
|
|
|
$total = dbFetchOne( "SELECT count(*) AS Total FROM Logs", 'Total' );
|
|
|
|
$sql = 'SELECT * FROM Logs';
|
2011-06-21 17:19:10 +08:00
|
|
|
$where = array();
|
2013-11-02 00:30:07 +08:00
|
|
|
$values = array();
|
2013-11-13 23:11:16 +08:00
|
|
|
if ( $minTime ) {
|
|
|
|
$where[] = "TimeKey > ?";
|
|
|
|
$values[] = $minTime;
|
|
|
|
} elseif ( $maxTime ) {
|
|
|
|
$where[] = "TimeKey < ?";
|
|
|
|
$values[] = $maxTime;
|
|
|
|
}
|
|
|
|
foreach ( $filter as $field=>$value ) {
|
|
|
|
if ( $field == 'Level' ){
|
|
|
|
$where[] = $field." <= ?";
|
|
|
|
$values[] = $value;
|
|
|
|
} else {
|
|
|
|
$where[] = $field." = ?";
|
|
|
|
$values[] = $value;
|
|
|
|
}
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( count($where) )
|
2014-09-27 02:43:58 +08:00
|
|
|
$sql.= ' WHERE '.join( ' AND ', $where );
|
2013-11-13 23:11:16 +08:00
|
|
|
$sql .= " order by ".$sortField." ".$sortOrder." limit ".$limit;
|
2011-06-21 17:19:10 +08:00
|
|
|
$logs = array();
|
2014-09-27 02:43:58 +08:00
|
|
|
foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) {
|
2011-06-21 17:19:10 +08:00
|
|
|
$log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] );
|
|
|
|
$logs[] = $log;
|
|
|
|
}
|
|
|
|
$options = array();
|
|
|
|
$where = array();
|
2013-11-13 23:11:16 +08:00
|
|
|
$values = array();
|
|
|
|
foreach( $filter as $field=>$value ) {
|
|
|
|
if ( $field == 'Level' ) {
|
|
|
|
$where[$field] = $field." <= ?";
|
|
|
|
$values[$field] = $value;
|
|
|
|
} else {
|
|
|
|
$where[$field] = $field." = ?";
|
|
|
|
$values[$field] = $value;
|
|
|
|
}
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
foreach( $filterFields as $field )
|
|
|
|
{
|
2014-09-27 02:43:58 +08:00
|
|
|
$sql = "SELECT DISTINCT $field FROM Logs WHERE NOT isnull($field)";
|
2011-06-24 05:53:45 +08:00
|
|
|
$fieldWhere = array_diff_key( $where, array( $field=>true ) );
|
2013-11-13 23:11:16 +08:00
|
|
|
$fieldValues = array_diff_key( $values, array( $field=>true ) );
|
2011-06-24 05:53:45 +08:00
|
|
|
if ( count($fieldWhere) )
|
2014-09-27 02:43:58 +08:00
|
|
|
$sql.= " AND ".join( ' AND ', $fieldWhere );
|
|
|
|
$sql.= " ORDER BY $field ASC";
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( $field == 'Level' )
|
|
|
|
{
|
2014-09-27 02:43:58 +08:00
|
|
|
foreach( dbFetchAll( $sql, $field, array_values($fieldValues) ) as $value )
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( $value <= Logger::INFO )
|
|
|
|
$options[$field][$value] = Logger::$codes[$value];
|
|
|
|
else
|
|
|
|
$options[$field][$value] = "DB".$value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-09-27 02:43:58 +08:00
|
|
|
foreach( dbFetchAll( $sql, $field, array_values( $fieldValues ) ) as $value )
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( $value != '' )
|
|
|
|
$options[$field][] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( count($filter) )
|
|
|
|
{
|
2014-09-27 02:43:58 +08:00
|
|
|
$sql = "SELECT count(*) AS Available FROM Logs WHERE ".join( ' AND ', $where );
|
|
|
|
$available = dbFetchOne( $sql, 'Available', array_values($values) );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
ajaxResponse( array(
|
|
|
|
'updated' => preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG ),
|
|
|
|
'total' => $total,
|
|
|
|
'available' => isset($available)?$available:$total,
|
|
|
|
'logs' => $logs,
|
|
|
|
'state' => logState(),
|
|
|
|
'options' => $options
|
|
|
|
) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'export' :
|
|
|
|
{
|
|
|
|
if ( !canView( 'System' ) )
|
|
|
|
ajaxError( 'Insufficient permissions to export logs' );
|
|
|
|
|
2011-08-26 18:50:50 +08:00
|
|
|
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
|
|
|
|
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime )
|
|
|
|
{
|
|
|
|
$tempTime = $minTime;
|
|
|
|
$minTime = $maxTime;
|
|
|
|
$maxTime = $tempTime;
|
|
|
|
}
|
2011-08-26 18:50:50 +08:00
|
|
|
//$limit = isset($_POST['limit'])?$_POST['limit']:1000;
|
|
|
|
$filter = isset($_POST['filter'])?$_POST['filter']:array();
|
|
|
|
$sortField = isset($_POST['sortField'])?$_POST['sortField']:'TimeKey';
|
|
|
|
$sortOrder = isset($_POST['sortOrder'])?$_POST['sortOrder']:'asc';
|
2011-06-21 17:19:10 +08:00
|
|
|
|
|
|
|
$sql = "select * from Logs";
|
|
|
|
$where = array();
|
2013-11-13 23:11:16 +08:00
|
|
|
$values = array();
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( $minTime )
|
|
|
|
{
|
|
|
|
preg_match( '/(.+)(\.\d+)/', $minTime, $matches );
|
|
|
|
$minTime = strtotime($matches[1]).$matches[2];
|
2013-11-13 23:11:16 +08:00
|
|
|
$where[] = "TimeKey >= ?";
|
|
|
|
$values[] = $minTime;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
if ( $maxTime )
|
|
|
|
{
|
|
|
|
preg_match( '/(.+)(\.\d+)/', $maxTime, $matches );
|
|
|
|
$maxTime = strtotime($matches[1]).$matches[2];
|
2013-11-13 23:11:16 +08:00
|
|
|
$where[] = "TimeKey <= ?";
|
|
|
|
$values[] = $maxTime;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2013-11-13 23:11:16 +08:00
|
|
|
foreach ( $filter as $field=>$value ) {
|
|
|
|
if ( $value != '' ) {
|
|
|
|
if ( $field == 'Level' ) {
|
|
|
|
$where[] = $field." <= ?";
|
|
|
|
$values[] = $value;
|
|
|
|
} else {
|
|
|
|
$where[] = $field." = ?'";
|
|
|
|
$values[] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( count($where) )
|
|
|
|
$sql.= " where ".join( " and ", $where );
|
2013-11-13 23:11:16 +08:00
|
|
|
$sql .= " order by ".$sortField." ".$sortOrder;
|
2011-06-21 17:19:10 +08:00
|
|
|
//$sql .= " limit ".dbEscape($limit);
|
2011-08-26 18:50:50 +08:00
|
|
|
$format = isset($_POST['format'])?$_POST['format']:'text';
|
2011-06-21 17:19:10 +08:00
|
|
|
switch( $format )
|
|
|
|
{
|
|
|
|
case 'text' :
|
|
|
|
$exportExt = "txt";
|
|
|
|
break;
|
|
|
|
case 'tsv' :
|
|
|
|
$exportExt = "tsv";
|
|
|
|
break;
|
|
|
|
case 'html' :
|
|
|
|
$exportExt = "html";
|
|
|
|
break;
|
|
|
|
case 'xml' :
|
|
|
|
$exportExt = "xml";
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
Fatal( "Unrecognised log export format '$format'" );
|
|
|
|
}
|
|
|
|
$exportKey = substr(md5(rand()),0,8);
|
|
|
|
$exportFile = "zm-log.$exportExt";
|
2015-01-04 04:16:19 +08:00
|
|
|
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
|
2011-06-21 17:19:10 +08:00
|
|
|
if ( !($exportFP = fopen( $exportPath, "w" )) )
|
2015-01-04 04:16:19 +08:00
|
|
|
Fatal( "Unable to open log export file $exportPath" );
|
2011-06-21 17:19:10 +08:00
|
|
|
$logs = array();
|
2013-11-13 23:11:16 +08:00
|
|
|
foreach ( dbFetchAll( $sql, NULL, $values ) as $log )
|
2011-06-21 17:19:10 +08:00
|
|
|
{
|
|
|
|
$log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] );
|
|
|
|
$logs[] = $log;
|
|
|
|
}
|
|
|
|
switch( $format )
|
|
|
|
{
|
|
|
|
case 'text' :
|
|
|
|
{
|
|
|
|
foreach ( $logs as $log )
|
|
|
|
{
|
|
|
|
if ( $log['Line'] )
|
|
|
|
fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] );
|
|
|
|
else
|
|
|
|
fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'tsv' :
|
|
|
|
{
|
|
|
|
fprintf( $exportFP, $SLANG['DateTime']."\t".$SLANG['Component']."\t".$SLANG['Pid']."\t".$SLANG['Level']."\t".$SLANG['Message']."\t".$SLANG['File']."\t".$SLANG['Line']."\n" );
|
|
|
|
foreach ( $logs as $log )
|
|
|
|
{
|
|
|
|
fprintf( $exportFP, "%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'html' :
|
|
|
|
{
|
|
|
|
fwrite( $exportFP,
|
|
|
|
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
|
|
<head>
|
|
|
|
<title>'.$SLANG['ZoneMinderLog'].'</title>
|
|
|
|
<style type="text/css">
|
|
|
|
body, h3, p, table, td {
|
|
|
|
font-family: Verdana, Arial, Helvetica, sans-serif;
|
|
|
|
font-size: 11px;
|
|
|
|
}
|
|
|
|
table {
|
|
|
|
border-collapse: collapse;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
th {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
th, td {
|
|
|
|
border: 1px solid #888888;
|
|
|
|
padding: 1px 2px;
|
|
|
|
}
|
|
|
|
tr.log-fat td {
|
|
|
|
background-color:#ffcccc;
|
|
|
|
font-weight: bold;
|
2011-06-24 05:53:45 +08:00
|
|
|
font-style: italic;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
tr.log-err td {
|
|
|
|
background-color:#ffcccc;
|
|
|
|
}
|
|
|
|
tr.log-war td {
|
|
|
|
background-color: #ffe4b5;
|
|
|
|
}
|
|
|
|
tr.log-dbg td {
|
2011-06-24 05:53:45 +08:00
|
|
|
color: #666666;
|
|
|
|
font-style: italic;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h3>'.$SLANG['ZoneMinderLog'].'</h3>
|
|
|
|
<p>'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'</p>
|
|
|
|
<p>'.count($logs).' '.$SLANG['Logs'].'</p>
|
|
|
|
<table>
|
|
|
|
<tbody>
|
|
|
|
<tr><th>'.$SLANG['DateTime'].'</th><th>'.$SLANG['Component'].'</th><th>'.$SLANG['Pid'].'</th><th>'.$SLANG['Level'].'</th><th>'.$SLANG['Message'].'</th><th>'.$SLANG['File'].'</th><th>'.$SLANG['Line'].'</th></tr>
|
|
|
|
' );
|
|
|
|
foreach ( $logs as $log )
|
|
|
|
{
|
|
|
|
$classLevel = $log['Level'];
|
|
|
|
if ( $classLevel < Logger::FATAL )
|
|
|
|
$classLevel = Logger::FATAL;
|
|
|
|
elseif ( $classLevel > Logger::DEBUG )
|
|
|
|
$classLevel = Logger::DEBUG;
|
|
|
|
$logClass = 'log-'.strtolower(Logger::$codes[$classLevel]);
|
|
|
|
fprintf( $exportFP, " <tr class=\"%s\"><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $logClass, $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
|
|
|
|
}
|
|
|
|
fwrite( $exportFP,
|
|
|
|
' </tbody>
|
|
|
|
</table>
|
|
|
|
</body>
|
|
|
|
</html>' );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'xml' :
|
|
|
|
{
|
|
|
|
fwrite( $exportFP,
|
|
|
|
'<?xml version="1.0" encoding="utf-8"?>
|
|
|
|
<logexport title="'.$SLANG['ZoneMinderLog'].'" date="'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'">
|
|
|
|
<selector>'.$_POST['selector'].'</selector>' );
|
|
|
|
foreach ( $filter as $field=>$value )
|
|
|
|
if ( $value != '' )
|
|
|
|
fwrite( $exportFP,
|
|
|
|
' <filter>
|
|
|
|
<'.strtolower($field).'>'.htmlspecialchars($value).'</'.strtolower($field).'>
|
|
|
|
</filter>' );
|
|
|
|
fwrite( $exportFP,
|
|
|
|
' <columns>
|
|
|
|
<column field="datetime">'.$SLANG['DateTime'].'</column><column field="component">'.$SLANG['Component'].'</column><column field="pid">'.$SLANG['Pid'].'</column><column field="level">'.$SLANG['Level'].'</column><column field="message">'.$SLANG['Message'].'</column><column field="file">'.$SLANG['File'].'</column><column field="line">'.$SLANG['Line'].'</column>
|
|
|
|
</columns>
|
|
|
|
<logs count="'.count($logs).'">
|
|
|
|
' );
|
|
|
|
foreach ( $logs as $log )
|
|
|
|
{
|
|
|
|
fprintf( $exportFP,
|
|
|
|
" <log>
|
|
|
|
<datetime>%s</datetime>
|
|
|
|
<component>%s</component>
|
|
|
|
<pid>%d</pid>
|
|
|
|
<level>%s</level>
|
|
|
|
<message><![CDATA[%s]]></message>
|
|
|
|
<file>%s</file>
|
|
|
|
<line>%d</line>
|
|
|
|
</log>\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] );
|
|
|
|
}
|
|
|
|
fwrite( $exportFP,
|
|
|
|
' </logs>
|
|
|
|
</logexport>' );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$exportExt = "xml";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fclose( $exportFP );
|
|
|
|
ajaxResponse( array(
|
|
|
|
'key' => $exportKey,
|
|
|
|
'format' => $format,
|
|
|
|
) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'download' :
|
|
|
|
{
|
|
|
|
if ( !canView( 'System' ) )
|
|
|
|
ajaxError( 'Insufficient permissions to download logs' );
|
|
|
|
|
|
|
|
if ( empty($_REQUEST['key']) )
|
|
|
|
Fatal( "No log export key given" );
|
|
|
|
$exportKey = $_REQUEST['key'];
|
|
|
|
if ( empty($_REQUEST['format']) )
|
|
|
|
Fatal( "No log export format given" );
|
|
|
|
$format = $_REQUEST['format'];
|
|
|
|
|
|
|
|
switch( $format )
|
|
|
|
{
|
|
|
|
case 'text' :
|
|
|
|
$exportExt = "txt";
|
|
|
|
break;
|
|
|
|
case 'tsv' :
|
|
|
|
$exportExt = "tsv";
|
|
|
|
break;
|
|
|
|
case 'html' :
|
|
|
|
$exportExt = "html";
|
|
|
|
break;
|
|
|
|
case 'xml' :
|
|
|
|
$exportExt = "xml";
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
Fatal( "Unrecognised log export format '$format'" );
|
|
|
|
}
|
|
|
|
|
|
|
|
$exportFile = "zm-log.$exportExt";
|
|
|
|
$exportPath = "temp/zm-log-$exportKey.$exportExt";
|
|
|
|
|
|
|
|
header( "Pragma: public" );
|
|
|
|
header( "Expires: 0" );
|
|
|
|
header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
|
|
|
|
header( "Cache-Control: private", false ); // required by certain browsers
|
|
|
|
header( "Content-Description: File Transfer" );
|
|
|
|
header( 'Content-Disposition: attachment; filename="'.$exportFile.'"' );
|
|
|
|
header( "Content-Transfer-Encoding: binary" );
|
|
|
|
header( "Content-Type: application/force-download" );
|
|
|
|
header( "Content-Length: ".filesize($exportPath) );
|
|
|
|
readfile( $exportPath );
|
|
|
|
exit( 0 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ajaxError( 'Unrecognised action or insufficient permissions' );
|
|
|
|
|
|
|
|
?>
|