Skip to content

Commit 33e0402

Browse files
Merge pull request #4524 from ZoneMinder/copilot/update-filter-dropdowns-ajax-request
Fix monitor filter AJAX persistence with stateless, cookie-only architecture
2 parents 8e71110 + cd1bb4b commit 33e0402

File tree

4 files changed

+200
-71
lines changed

4 files changed

+200
-71
lines changed

web/ajax/console.php

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -91,36 +91,34 @@ function queryRequest() {
9191
$sort = isset($_REQUEST['sort']) ? $_REQUEST['sort'] : 'Sequence';
9292
$order = isset($_REQUEST['order']) ? strtoupper($_REQUEST['order']) : 'ASC';
9393

94-
// Build monitor query with filters from session
95-
zm_session_start();
94+
// Build monitor query with filters from request parameters (stateless)
9695
$conditions = array();
9796
$values = array();
9897

99-
// Store session filters for later use
100-
$session_filters = array(
101-
'GroupId' => isset($_SESSION['GroupId']) ? $_SESSION['GroupId'] : null,
102-
'ServerId' => isset($_SESSION['ServerId']) ? $_SESSION['ServerId'] : null,
103-
'StorageId' => isset($_SESSION['StorageId']) ? $_SESSION['StorageId'] : null,
104-
'Capturing' => isset($_SESSION['Capturing']) ? $_SESSION['Capturing'] : null,
105-
'Analysing' => isset($_SESSION['Analysing']) ? $_SESSION['Analysing'] : null,
106-
'Recording' => isset($_SESSION['Recording']) ? $_SESSION['Recording'] : null,
107-
'Status' => isset($_SESSION['Status']) ? $_SESSION['Status'] : null,
108-
'MonitorName' => isset($_SESSION['MonitorName']) ? $_SESSION['MonitorName'] : null,
109-
'Source' => isset($_SESSION['Source']) ? $_SESSION['Source'] : null
98+
// Get filter values directly from request
99+
$request_filters = array(
100+
'GroupId' => isset($_REQUEST['GroupId']) ? $_REQUEST['GroupId'] : null,
101+
'ServerId' => isset($_REQUEST['ServerId']) ? $_REQUEST['ServerId'] : null,
102+
'StorageId' => isset($_REQUEST['StorageId']) ? $_REQUEST['StorageId'] : null,
103+
'Capturing' => isset($_REQUEST['Capturing']) ? $_REQUEST['Capturing'] : null,
104+
'Analysing' => isset($_REQUEST['Analysing']) ? $_REQUEST['Analysing'] : null,
105+
'Recording' => isset($_REQUEST['Recording']) ? $_REQUEST['Recording'] : null,
106+
'Status' => isset($_REQUEST['Status']) ? $_REQUEST['Status'] : null,
107+
'MonitorId' => isset($_REQUEST['MonitorId']) ? $_REQUEST['MonitorId'] : null,
108+
'MonitorName' => isset($_REQUEST['MonitorName']) ? $_REQUEST['MonitorName'] : null,
109+
'Source' => isset($_REQUEST['Source']) ? $_REQUEST['Source'] : null
110110
);
111111

112-
session_write_close();
113-
114-
// Apply session filters to SQL
115-
if ($session_filters['GroupId']) {
116-
$GroupIds = is_array($session_filters['GroupId']) ? $session_filters['GroupId'] : array($session_filters['GroupId']);
112+
// Apply request filters to SQL
113+
if ($request_filters['GroupId']) {
114+
$GroupIds = is_array($request_filters['GroupId']) ? $request_filters['GroupId'] : array($request_filters['GroupId']);
117115
$conditions[] = 'M.Id IN (SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (' . implode(',', array_fill(0, count($GroupIds), '?')) . '))';
118116
$values = array_merge($values, $GroupIds);
119117
}
120118

121119
foreach (array('ServerId','StorageId') as $filter) {
122-
if ($session_filters[$filter]) {
123-
$filter_values = is_array($session_filters[$filter]) ? $session_filters[$filter] : array($session_filters[$filter]);
120+
if ($request_filters[$filter]) {
121+
$filter_values = is_array($request_filters[$filter]) ? $request_filters[$filter] : array($request_filters[$filter]);
124122
if (count($filter_values)) {
125123
$conditions[] = 'M.'.$filter.' IN (' . implode(',', array_fill(0, count($filter_values), '?')) . ')';
126124
$values = array_merge($values, $filter_values);
@@ -129,17 +127,17 @@ function queryRequest() {
129127
}
130128

131129
foreach (array('Capturing','Analysing','Recording') as $filter) {
132-
if ($session_filters[$filter]) {
133-
$filter_values = is_array($session_filters[$filter]) ? $session_filters[$filter] : array($session_filters[$filter]);
130+
if ($request_filters[$filter]) {
131+
$filter_values = is_array($request_filters[$filter]) ? $request_filters[$filter] : array($request_filters[$filter]);
134132
if (count($filter_values)) {
135133
$conditions[] = 'M.'.$filter.' IN (' . implode(',', array_fill(0, count($filter_values), '?')) . ')';
136134
$values = array_merge($values, $filter_values);
137135
}
138136
}
139137
}
140138

141-
if ($session_filters['Status']) {
142-
$status_values = is_array($session_filters['Status']) ? $session_filters['Status'] : array($session_filters['Status']);
139+
if ($request_filters['Status']) {
140+
$status_values = is_array($request_filters['Status']) ? $request_filters['Status'] : array($request_filters['Status']);
143141
if (count($status_values)) {
144142
$conditions[] = 'COALESCE(S.Status, IF(M.Type="WebSite","Running","NotRunning")) IN (' . implode(',', array_fill(0, count($status_values), '?')) . ')';
145143
$values = array_merge($values, $status_values);
@@ -185,17 +183,17 @@ function queryRequest() {
185183
});
186184
}
187185

188-
// Apply MonitorName and Source session filters
189-
if ($session_filters['MonitorName']) {
190-
$regexp = $session_filters['MonitorName'];
186+
// Apply MonitorName and Source request filters
187+
if ($request_filters['MonitorName']) {
188+
$regexp = $request_filters['MonitorName'];
191189
if (!strpos($regexp, '/')) $regexp = '/'.$regexp.'/i';
192190
$filtered_monitors = array_filter($filtered_monitors, function($monitor) use ($regexp) {
193191
return @preg_match($regexp, $monitor['Name']);
194192
});
195193
}
196194

197-
if ($session_filters['Source']) {
198-
$regexp = $session_filters['Source'];
195+
if ($request_filters['Source']) {
196+
$regexp = $request_filters['Source'];
199197
if (!preg_match("/^\/.+\/[a-z]*$/i", $regexp))
200198
$regexp = '/'.$regexp.'/i';
201199
$filtered_monitors = array_filter($filtered_monitors, function($monitor) use ($regexp) {
@@ -204,6 +202,14 @@ function queryRequest() {
204202
});
205203
}
206204

205+
// Apply MonitorId filter
206+
if ($request_filters['MonitorId']) {
207+
$monitor_ids = is_array($request_filters['MonitorId']) ? $request_filters['MonitorId'] : array($request_filters['MonitorId']);
208+
$filtered_monitors = array_filter($filtered_monitors, function($monitor) use ($monitor_ids) {
209+
return in_array($monitor['Id'], $monitor_ids);
210+
});
211+
}
212+
207213
$data['total'] = count($filtered_monitors);
208214

209215
// Sort monitors
@@ -287,6 +293,7 @@ function queryRequest() {
287293
$row['Name'] = validHtmlStr($monitor['Name']);
288294
$row['Function'] = $monitor['Function'];
289295
$row['Enabled'] = $monitor['Enabled'];
296+
$row['Sequence'] = isset($monitor['Sequence']) ? $monitor['Sequence'] : 0;
290297

291298
// Status
292299
if (!$monitor['Status']) {

web/includes/Group.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,23 @@ public function MonitorIds( ) {
6767
return $this->{'MonitorIds'};
6868
}
6969

70-
public static function get_group_dropdown( ) {
71-
$selected_group_id = 0;
72-
if ( isset($_REQUEST['groups']) ) {
73-
$selected_group_id = $group_id = $_SESSION['groups'] = $_REQUEST['groups'];
74-
} else if ( isset( $_SESSION['groups'] ) ) {
75-
$selected_group_id = $group_id = $_SESSION['groups'];
76-
} else if ( isset($_REQUEST['filtering']) ) {
77-
zm_session_start();
78-
unset($_SESSION['groups']);
79-
session_write_close();
70+
public static function get_group_dropdown( $view = null ) {
71+
// Get selected value from cookie
72+
$selectedValue = null;
73+
if (isset($_COOKIE['zmFilter_GroupId'])) {
74+
$cookieValue = $_COOKIE['zmFilter_GroupId'];
75+
if ($cookieValue && $cookieValue !== '') {
76+
// Try to decode JSON for array values
77+
$decoded = json_decode($cookieValue, true);
78+
$selectedValue = ($decoded !== null) ? $decoded : $cookieValue;
79+
}
8080
}
8181

82-
return htmlSelect('GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
83-
'data-on-change' => 'submitThisForm',
82+
// Use monitorFilterOnChange on console view for AJAX refresh, submitThisForm elsewhere
83+
$onChangeFunction = ($view == 'console') ? 'monitorFilterOnChange' : 'submitThisForm';
84+
85+
return htmlSelect('GroupId[]', Group::get_dropdown_options(), $selectedValue, array(
86+
'data-on-change' => $onChangeFunction,
8487
'class'=>'chosen',
8588
'multiple'=>'multiple',
8689
'data-placeholder'=>'All',

web/skins/classic/views/_monitor_filters.php

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,21 @@ function addFilterSelect($name, $options) {
2323
// Use monitorFilterOnChange on console view for AJAX refresh, submitThisForm elsewhere
2424
$onChangeFunction = ($view == 'console') ? 'monitorFilterOnChange' : 'submitThisForm';
2525

26+
// Get selected value from cookie only
27+
$selectedValue = '';
28+
if (isset($_COOKIE['zmFilter_'.$name])) {
29+
$cookieValue = $_COOKIE['zmFilter_'.$name];
30+
if ($cookieValue && $cookieValue !== '') {
31+
// Try to decode JSON for array values
32+
$decoded = json_decode($cookieValue, true);
33+
$selectedValue = ($decoded !== null) ? $decoded : $cookieValue;
34+
}
35+
}
36+
2637
$html = '<span class="term '.$name.'Filter"><label>'.translate($name).'</label>';
2738
$html .= '<span class="term-value-wrapper">';
2839
$html .= htmlSelect($name.'[]', $options,
29-
(isset($_SESSION[$name])?$_SESSION[$name]:''),
40+
$selectedValue,
3041
array(
3142
'data-on-change'=>$onChangeFunction,
3243
'class'=>'chosen',
@@ -62,19 +73,19 @@ function buildMonitorsFilters() {
6273
// Use monitorFilterOnChange on console view for AJAX refresh, submitThisForm elsewhere
6374
$onChangeFunction = ($view == 'console') ? 'monitorFilterOnChange' : 'submitThisForm';
6475

65-
zm_session_start();
66-
foreach (array('GroupId','Capturing','Analysing','Recording','ServerId','StorageId','Status','MonitorId','MonitorName','Source') as $var) {
67-
if (isset($_REQUEST[$var])) {
68-
if ($_REQUEST[$var] != '') {
69-
$_SESSION[$var] = $_REQUEST[$var];
70-
} else {
71-
unset($_SESSION[$var]);
76+
// Helper function to get filter value from cookie
77+
function getFilterFromCookie($var) {
78+
$cookieName = 'zmFilter_'.$var;
79+
if (isset($_COOKIE[$cookieName])) {
80+
$cookieValue = $_COOKIE[$cookieName];
81+
if ($cookieValue && $cookieValue !== '') {
82+
// Try to decode JSON for array values
83+
$decoded = json_decode($cookieValue, true);
84+
return ($decoded !== null) ? $decoded : $cookieValue;
7285
}
73-
} else if (isset($_REQUEST['filtering'])) {
74-
unset($_SESSION[$var]);
7586
}
87+
return null;
7688
}
77-
session_write_close();
7889

7990
$storage_areas = ZM\Storage::find();
8091
$StorageById = array();
@@ -106,17 +117,19 @@ function buildMonitorsFilters() {
106117
$html .= '<span class="term" id="groupControl"><label>'. translate('Group') .'</label>';
107118
$html .= '<span class="term-value-wrapper">';
108119
# This will end up with the group_id of the deepest selection
109-
$group_id = isset($_SESSION['GroupId']) ? $_SESSION['GroupId'] : null;
110-
$html .= ZM\Group::get_group_dropdown();
120+
$group_id = getFilterFromCookie('GroupId');
121+
$html .= ZM\Group::get_group_dropdown($view);
111122
$groupSql = ZM\Group::get_group_sql($group_id);
112123
$html .= addButtonResetForFilterSelect('GroupId[]');
113124
$html .= '</span>';
114125
$html .= '</span>';
115126
}
116127
}
117128

118-
$selected_monitor_ids = isset($_SESSION['MonitorId']) ? $_SESSION['MonitorId'] : array();
119-
if ( !is_array($selected_monitor_ids) ) {
129+
$selected_monitor_ids = getFilterFromCookie('MonitorId');
130+
if (!$selected_monitor_ids) {
131+
$selected_monitor_ids = array();
132+
} else if (!is_array($selected_monitor_ids)) {
120133
$selected_monitor_ids = array($selected_monitor_ids);
121134
}
122135

@@ -126,13 +139,14 @@ function buildMonitorsFilters() {
126139
if ( $groupSql )
127140
$conditions[] = $groupSql;
128141
foreach ( array('ServerId','StorageId','Status','Capturing','Analysing','Recording') as $filter ) {
129-
if ( isset($_SESSION[$filter]) ) {
130-
if ( is_array($_SESSION[$filter]) ) {
131-
$conditions[] = '`'.$filter . '` IN ('.implode(',', array_map(function(){return '?';}, $_SESSION[$filter])). ')';
132-
$values = array_merge($values, $_SESSION[$filter]);
142+
$filterValue = getFilterFromCookie($filter);
143+
if ( $filterValue ) {
144+
if ( is_array($filterValue) ) {
145+
$conditions[] = '`'.$filter . '` IN ('.implode(',', array_map(function(){return '?';}, $filterValue)).')';
146+
$values = array_merge($values, $filterValue);
133147
} else {
134148
$conditions[] = '`'.$filter . '`=?';
135-
$values[] = $_SESSION[$filter];
149+
$values[] = $filterValue;
136150
}
137151
}
138152
} # end foreach filter
@@ -143,9 +157,10 @@ function buildMonitorsFilters() {
143157
$values = array_merge($values, $ids);
144158
}
145159

160+
$monitorNameValue = getFilterFromCookie('MonitorName');
146161
$html .= '<span class="term MonitorNameFilter"><label>'.translate('Name').'</label>';
147162
$html .= '<span class="term-value-wrapper">';
148-
$html .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="'.translate('text or regular expression').'"/></span>';
163+
$html .= '<input type="text" name="MonitorName" value="'.($monitorNameValue ? validHtmlStr($monitorNameValue) : '').'" placeholder="'.translate('text or regular expression').'"/></span>';
149164
$html .= '</span>'.PHP_EOL;
150165

151166
$html .= addFilterSelect('Capturing', array('None'=>translate('None'), 'Always'=>translate('Always'), 'OnDemand'=>translate('On Demand')));
@@ -156,7 +171,7 @@ function buildMonitorsFilters() {
156171
$html .= '<span class="term ServerFilter"><label>'. translate('Server').'</label>';
157172
$html .= '<span class="term-value-wrapper">';
158173
$html .= htmlSelect('ServerId[]', $ServersById,
159-
(isset($_SESSION['ServerId'])?$_SESSION['ServerId']:''),
174+
getFilterFromCookie('ServerId') ?: '',
160175
array(
161176
'data-on-change'=>$onChangeFunction,
162177
'class'=>'chosen',
@@ -173,7 +188,7 @@ function buildMonitorsFilters() {
173188
$html .= '<span class="term StorageFilter"><label>'.translate('Storage').'</label>';
174189
$html .= '<span class="term-value-wrapper">';
175190
$html .= htmlSelect('StorageId[]', $StorageById,
176-
(isset($_SESSION['StorageId'])?$_SESSION['StorageId']:''),
191+
getFilterFromCookie('StorageId') ?: '',
177192
array(
178193
'data-on-change'=>$onChangeFunction,
179194
'class'=>'chosen',
@@ -194,7 +209,7 @@ function buildMonitorsFilters() {
194209
);
195210
$html .= '<span class="term-value-wrapper">';
196211
$html .= htmlSelect( 'Status[]', $status_options,
197-
( isset($_SESSION['Status']) ? $_SESSION['Status'] : '' ),
212+
getFilterFromCookie('Status') ?: '',
198213
array(
199214
'data-on-change'=>$onChangeFunction,
200215
'class'=>'chosen',
@@ -205,9 +220,10 @@ function buildMonitorsFilters() {
205220
$html .= '</span>';
206221
$html .= '</span>';
207222

223+
$sourceValue = getFilterFromCookie('Source');
208224
$html .= '<span class="term SourceFilter"><label>'.translate('Source').'</label>';
209225
$html .= '<span class="term-value-wrapper">';
210-
$html .= '<input type="text" name="Source" value="'.(isset($_SESSION['Source'])?validHtmlStr($_SESSION['Source']):'').'" placeholder="'.translate('text or regular expression').'"/>';
226+
$html .= '<input type="text" name="Source" value="'.($sourceValue ? validHtmlStr($sourceValue) : '').'" placeholder="'.translate('text or regular expression').'"/>';
211227
$html .= '</span>';
212228
$html .= '</span>';
213229

@@ -252,11 +268,12 @@ function buildMonitorsFilters() {
252268
continue;
253269
}
254270

255-
if ( isset($_SESSION['MonitorName']) ) {
271+
$monitorNameFilter = getFilterFromCookie('MonitorName');
272+
if ( $monitorNameFilter ) {
256273
$Monitor = new ZM\Monitor($monitors[$i]);
257274
ini_set('track_errors', 'on');
258275
$php_errormsg = '';
259-
$regexp = $_SESSION['MonitorName'];
276+
$regexp = $monitorNameFilter;
260277
if (!strpos($regexp, '/')) $regexp = '/'.$regexp.'/i';
261278

262279
@preg_match($regexp, '');
@@ -269,18 +286,19 @@ function buildMonitorsFilters() {
269286
}
270287
}
271288

272-
if ( isset($_SESSION['Source']) ) {
289+
$sourceFilter = getFilterFromCookie('Source');
290+
if ( $sourceFilter ) {
273291
$Monitor = new ZM\Monitor($monitors[$i]);
274292
ini_set('track_errors', 'on');
275293
$php_errormsg = '';
276-
$regexp = $_SESSION['Source'];
294+
$regexp = $sourceFilter;
277295

278296
if (!preg_match("/^\/.+\/[a-z]*$/i",$regexp))
279297
$regexp = '/'.$regexp.'/i';
280298

281299
@preg_match($regexp, '');
282300
if ( $php_errormsg ) {
283-
ZM\Warning($_SESSION['Source'].' is not a valid search string');
301+
ZM\Warning($sourceFilter.' is not a valid search string');
284302
} else {
285303
ZM\Debug("Using $regexp for source");
286304
if ( !preg_match($regexp, $Monitor->Source()) ) {

0 commit comments

Comments
 (0)