1<?php 2$data = array(); 3$message = ''; 4 5// 6// INITIALIZE AND CHECK SANITY 7// 8 9if ( !canView('System') ) 10 $message = 'Insufficient permissions to view log entries for user '.$user['Username']; 11 12// task must be set 13if ( !isset($_REQUEST['task']) ) { 14 $message = 'This request requires a task to be set'; 15} else if ( $_REQUEST['task'] != 'query' && $_REQUEST['task'] != 'create' ) { 16 // Only the query and create tasks are supported at the moment 17 $message = 'Unrecognised task '.$_REQUEST['task']; 18} else { 19 $task = $_REQUEST['task']; 20} 21 22if ( $message ) { 23 ajaxError($message); 24 return; 25} 26 27// 28// MAIN LOOP 29// 30 31switch ( $task ) { 32 case 'create' : 33 createRequest(); 34 break; 35 case 'query' : 36 $data = queryRequest(); 37 break; 38 default : 39 ZM\Fatal('Unrecognised task '.$task); 40} // end switch task 41 42ajaxResponse($data); 43 44// 45// FUNCTION DEFINITIONS 46// 47 48function createRequest() { 49 if ( !empty($_POST['level']) && !empty($_POST['message']) ) { 50 ZM\logInit(array('id'=>'web_js')); 51 52 $string = $_POST['message']; 53 54 $file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : ''; 55 if ( !empty($_POST['line']) ) { 56 $line = validInt($_POST['line']); 57 } else { 58 $line = NULL; 59 } 60 61 $levels = array_flip(ZM\Logger::$codes); 62 if ( !isset($levels[$_POST['level']]) ) { 63 ZM\Panic('Unexpected logger level '.$_POST['level']); 64 } 65 $level = $levels[$_POST['level']]; 66 ZM\Logger::fetch()->logPrint($level, $string, $file, $line); 67 } else { 68 ZM\Error('Invalid log create: '.print_r($_POST, true)); 69 } 70} 71 72function queryRequest() { 73 74 // Offset specifies the starting row to return, used for pagination 75 $offset = 0; 76 if ( isset($_REQUEST['offset']) ) { 77 if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { 78 ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); 79 } else { 80 $offset = $_REQUEST['offset']; 81 } 82 } 83 84 // Limit specifies the number of rows to return 85 $limit = 100; 86 if ( isset($_REQUEST['limit']) ) { 87 if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { 88 ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); 89 } else { 90 $limit = $_REQUEST['limit']; 91 } 92 } 93 // The table we want our data from 94 $table = 'Logs'; 95 96 // The names of the dB columns in the log table we are interested in 97 $columns = array('TimeKey', 'Component', 'ServerId', 'Pid', 'Code', 'Message', 'File', 'Line'); 98 99 // The names of columns shown in the log view that are NOT dB columns in the database 100 $col_alt = array('DateTime', 'Server'); 101 102 $sort = 'TimeKey'; 103 if ( isset($_REQUEST['sort']) ) { 104 $sort = $_REQUEST['sort']; 105 if ( $sort == 'DateTime' ) $sort = 'TimeKey'; 106 } 107 if ( !in_array($sort, array_merge($columns, $col_alt)) ) { 108 ZM\Error('Invalid sort field: ' . $sort); 109 return; 110 } 111 112 // Order specifies the sort direction, either asc or desc 113 $order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; 114 115 $col_str = implode(', ', $columns); 116 $data = array(); 117 $query = array(); 118 $query['values'] = array(); 119 $likes = array(); 120 $where = ''; 121 // There are two search bars in the log view, normal and advanced 122 // Making an exuctive decision to ignore the normal search, when advanced search is in use 123 // Alternatively we could try to do both 124 // 125 // Advanced search contains an array of "column name" => "search text" pairs 126 // Bootstrap table sends json_ecoded array, which we must decode 127 $advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); 128 // Search contains a user entered string to search on 129 $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; 130 if ( count($advsearch) ) { 131 132 foreach ( $advsearch as $col=>$text ) { 133 if ( !in_array($col, array_merge($columns, $col_alt)) ) { 134 ZM\Error("'$col' is not a searchable column name"); 135 continue; 136 } 137 // Don't use wildcards on advanced search 138 //$text = '%' .$text. '%'; 139 array_push($likes, $col.' LIKE ?'); 140 array_push($query['values'], $text); 141 } 142 $wherevalues = $query['values']; 143 $where = ' WHERE (' .implode(' OR ', $likes). ')'; 144 145 } else if ( $search != '' ) { 146 147 $search = '%' .$search. '%'; 148 foreach ( $columns as $col ) { 149 array_push($likes, $col.' LIKE ?'); 150 array_push($query['values'], $search); 151 } 152 $wherevalues = $query['values']; 153 $where = ' WHERE (' .implode(' OR ', $likes). ')'; 154 } 155 156 $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; 157 array_push($query['values'], $offset, $limit); 158 159 $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); 160 if ( $search != '' || count($advsearch) ) { 161 $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); 162 } else { 163 $data['total'] = $data['totalNotFiltered']; 164 } 165 166 $rows = array(); 167 $results = dbFetchAll($query['sql'], NULL, $query['values']); 168 169 foreach ( $results as $row ) { 170 $row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey'])); 171 $Server = ZM\Server::find_one(array('Id'=>$row['ServerId'])); 172 173 $row['Server'] = $Server ? $Server->Name() : ''; 174 // First strip out any html tags 175 // Second strip out all characters that are not ASCII 32-126 (yes, 126) 176 $row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message'])); 177 $rows[] = $row; 178 } 179 $data['rows'] = $rows; 180 $data['logstate'] = logState(); 181 $data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG); 182 183 return $data; 184} 185