From eee3729b854cb6e40d9f5fb1698c1e2ea60e35aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Dec 2019 22:23:55 -0500 Subject: [PATCH 01/82] dirty fix filtering Monitors by GroupId. Change occurrences of GroupId to ' ' as that is what the key is in conditions. Please note that other operators like != won't work. --- web/api/app/Controller/MonitorsController.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 3be9166b8..eb229975b 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -36,7 +36,7 @@ class MonitorsController extends AppController { * @return void */ public function index() { - $this->Monitor->recursive = 0; + $this->Monitor->recursive = 1; if ( $this->request->params['named'] ) { $this->FilterComponent = $this->Components->load('Filter'); @@ -44,21 +44,21 @@ class MonitorsController extends AppController { } else { $conditions = array(); } - global $user; $allowedMonitors = $user ? preg_split('@,@', $user['MonitorIds'], NULL, PREG_SPLIT_NO_EMPTY) : null; if ( $allowedMonitors ) { $conditions['Monitor.Id' ] = $allowedMonitors; } - $find_array = array('conditions'=>$conditions,'contain'=>array('Group')); - if ( isset($conditions['GroupId']) ) { + $find_array = array('conditions'=>&$conditions,'contain'=>array('Group')); + if ( isset($conditions['`GroupId` ']) ) { $find_array['joins'] = array( array( 'table' => 'Groups_Monitors', 'type' => 'inner', 'conditions' => array( - 'Groups_Monitors.MonitorId = Monitor.Id' + 'Groups_Monitors.MonitorId = Monitor.Id', + 'Groups_Monitors.GroupId' => $conditions['`GroupId` '] ), ), //array( @@ -70,6 +70,7 @@ class MonitorsController extends AppController { //), //) ); + unset($conditions['`GroupId` ']); } $monitors = $this->Monitor->find('all',$find_array); $this->set(array( From 4b786eaad57397be54bde84db0a103bd3d1c3702 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Dec 2019 14:31:06 -0500 Subject: [PATCH 02/82] fix errors when ['id'] does not exist, and move the definition of values up because we use it outside the block it is defined in --- web/ajax/status.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index a553eaa04..2725dcce8 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -83,8 +83,8 @@ $statusData = array( 'MinEventId' => array( 'sql' => '(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id' ), 'MaxEventId' => array( 'sql' => '(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id' ), 'TotalEvents' => array( 'sql' => '(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id' ), - 'Status' => array( 'zmu' => '-m '.escapeshellarg($_REQUEST['id'][0]).' -s' ), - 'FrameRate' => array( 'zmu' => '-m '.escapeshellarg($_REQUEST['id'][0]).' -f' ), + 'Status' => (isset($_REQUEST['id'])?array( 'zmu' => '-m '.escapeshellarg($_REQUEST['id'][0]).' -s' ):null), + 'FrameRate' => (isset($_REQUEST['id'])?array( 'zmu' => '-m '.escapeshellarg($_REQUEST['id'][0]).' -f' ):null), ), ), 'events' => array( @@ -204,6 +204,7 @@ function collectData() { $fieldSql = array(); $joinSql = array(); $groupSql = array(); + $values = array(); $elements = &$entitySpec['elements']; $lc_elements = array_change_key_case( $elements ); @@ -258,7 +259,6 @@ function collectData() { if ( $id && !empty($entitySpec['selector']) ) { $index = 0; $where = array(); - $values = array(); foreach( $entitySpec['selector'] as $selIndex => $selector ) { $selectorParamName = ':selector' . $selIndex; if ( is_array( $selector ) ) { From 4632bbd12424068ece63a3652470bc09a00ea593 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 7 Dec 2019 11:45:32 -0500 Subject: [PATCH 03/82] Apply relevant changes to deal with php7,4 deprecations --- web/includes/Event.php | 14 ++-- web/includes/Filter.php | 4 +- web/includes/Group.php | 6 +- web/includes/Monitor.php | 30 ++++---- web/includes/MontageLayout.php | 127 +++------------------------------ web/includes/Object.php | 8 +-- web/includes/Storage.php | 10 +-- web/includes/database.php | 12 +--- 8 files changed, 47 insertions(+), 164 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 460d6eaa1..da633f439 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -51,10 +51,10 @@ class Event extends ZM_Object { if ( $new ) { $this->{'Storage'} = $new; } - if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) { + if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) { if ( isset($this->{'StorageId'}) and $this->{'StorageId'} ) $this->{'Storage'} = Storage::find_one(array('Id'=>$this->{'StorageId'})); - if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) + if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) $this->{'Storage'} = new Storage(NULL); } return $this->{'Storage'}; @@ -64,10 +64,10 @@ class Event extends ZM_Object { if ( $new ) { $this->{'SecondaryStorage'} = $new; } - if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) ) { + if ( ! ( property_exists($this, 'SecondaryStorage') and $this->{'SecondaryStorage'} ) ) { if ( isset($this->{'SecondaryStorageId'}) and $this->{'SecondaryStorageId'} ) $this->{'SecondaryStorage'} = Storage::find_one(array('Id'=>$this->{'SecondaryStorageId'})); - if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) ) + if ( ! ( property_exists($this, 'SecondaryStorage') and $this->{'SecondaryStorage'} ) ) $this->{'SecondaryStorage'} = new Storage(NULL); } return $this->{'SecondaryStorage'}; @@ -262,7 +262,7 @@ class Event extends ZM_Object { if ( is_null($new) or ( $new != '' ) ) { $this->{'DiskSpace'} = $new; } - if ( (!array_key_exists('DiskSpace',$this)) or (null === $this->{'DiskSpace'}) ) { + if ( (!property_exists($this, 'DiskSpace')) or (null === $this->{'DiskSpace'}) ) { $this->{'DiskSpace'} = folder_size($this->Path()); dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'})); } @@ -298,7 +298,7 @@ class Event extends ZM_Object { } // end function createListThumbnail function ThumbnailWidth( ) { - if ( ! ( array_key_exists('ThumbnailWidth', $this) ) ) { + if ( ! ( property_exists($this, 'ThumbnailWidth') ) ) { if ( ZM_WEB_LIST_THUMB_WIDTH ) { $this->{'ThumbnailWidth'} = ZM_WEB_LIST_THUMB_WIDTH; $scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_WIDTH)/$this->{'Width'}; @@ -315,7 +315,7 @@ class Event extends ZM_Object { } // end function ThumbnailWidth function ThumbnailHeight( ) { - if ( ! ( array_key_exists('ThumbnailHeight', $this) ) ) { + if ( ! ( property_exists($this, 'ThumbnailHeight') ) ) { if ( ZM_WEB_LIST_THUMB_WIDTH ) { $this->{'ThumbnailWidth'} = ZM_WEB_LIST_THUMB_WIDTH; $scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_WIDTH)/$this->{'Width'}; diff --git a/web/includes/Filter.php b/web/includes/Filter.php index fa7c41bff..2ecf7b61e 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -39,8 +39,8 @@ class Filter extends ZM_Object { $this->{'Query'} = func_get_arg(0);; $this->{'Query_json'} = jsonEncode($this->{'Query'}); } - if ( !array_key_exists('Query', $this) ) { - if ( array_key_exists('Query_json', $this) and $this->{'Query_json'} ) { + if ( !property_exists($this, 'Query') ) { + if ( property_exists($this, 'Query_json') and $this->{'Query_json'} ) { $this->{'Query'} = jsonDecode($this->{'Query_json'}); } else { $this->{'Query'} = array(); diff --git a/web/includes/Group.php b/web/includes/Group.php index b329946a3..3a34e0af4 100644 --- a/web/includes/Group.php +++ b/web/includes/Group.php @@ -18,7 +18,7 @@ class Group extends ZM_Object { } public function delete() { - if ( array_key_exists('Id', $this) ) { + if ( property_exists($this, 'Id') ) { dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'})); dbQuery('UPDATE Groups SET ParentId=NULL WHERE ParentId=?', array($this->{'Id'})); dbQuery('DELETE FROM Groups WHERE Id=?', array($this->{'Id'})); @@ -35,7 +35,7 @@ class Group extends ZM_Object { if ( isset($new) ) { $this->{'depth'} = $new; } - if ( !array_key_exists('depth', $this) or ($this->{'depth'} === null) ) { + if ( !property_exists($this, 'depth') or ($this->{'depth'} === null) ) { $this->{'depth'} = 0; if ( $this->{'ParentId'} != null ) { $Parent = Group::find_one(array('Id'=>$this->{'ParentId'})); @@ -46,7 +46,7 @@ class Group extends ZM_Object { } // end public function depth public function MonitorIds( ) { - if ( ! array_key_exists('MonitorIds', $this) ) { + if ( ! property_exists($this, 'MonitorIds') ) { $this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'})); } return $this->{'MonitorIds'}; diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index a9be54405..747fffea6 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -116,11 +116,11 @@ private $status_fields = array( ); public function Control() { - if ( !array_key_exists('Control', $this) ) { + if ( !property_exists($this, 'Control') ) { if ( $this->ControlId() ) $this->{'Control'} = Control::find_one(array('Id'=>$this->{'ControlId'})); - if ( !(array_key_exists('Control', $this) and $this->{'Control'}) ) + if ( !(property_exists($this, 'Control') and $this->{'Control'}) ) $this->{'Control'} = new Control(); } return $this->{'Control'}; @@ -138,7 +138,7 @@ private $status_fields = array( $this->{$fn} = $args[0]; } } - if ( array_key_exists($fn, $this) ) { + if ( property_exists($this, $fn) ) { return $this->{$fn}; } else if ( array_key_exists($fn, $this->defaults) ) { if ( is_array($this->defaults[$fn]) ) { @@ -211,9 +211,9 @@ private $status_fields = array( $this->{'Width'} = $new; $field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Height' : 'Width'; - if ( array_key_exists($field, $this) ) + if ( property_exists($this, $field) ) return $this->{$field}; - return $this->defaults{$field}; + return $this->defaults[$field]; } // end function Width public function ViewHeight($new=null) { @@ -221,9 +221,9 @@ private $status_fields = array( $this->{'Height'} = $new; $field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Width' : 'Height'; - if ( array_key_exists($field, $this) ) + if ( property_exists($this, $field) ) return $this->{$field}; - return $this->defaults{$field}; + return $this->defaults[$field]; } // end function Height public function SignalCheckColour($new=null) { @@ -234,10 +234,10 @@ private $status_fields = array( // Validate that it's a valid colour (we seem to allow color names, not just hex). // This also helps prevent XSS. - if (array_key_exists($field, $this) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) { + if ( property_exists($this, $field) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) { return $this->{$field}; } - return $this->defaults{$field}; + return $this->defaults[$field]; } // end function SignalCheckColour public static function find( $parameters = array(), $options = array() ) { @@ -253,7 +253,7 @@ private $status_fields = array( Warning('Attempt to control a monitor with no Id'); return; } - if ( (!defined('ZM_SERVER_ID')) or ( array_key_exists('ServerId', $this) and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { + if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { if ( $this->Type() == 'Local' ) { $zmcArgs = '-d '.$this->{'Device'}; } else { @@ -306,7 +306,7 @@ private $status_fields = array( return; } - if ( (!defined('ZM_SERVER_ID')) or ( array_key_exists('ServerId', $this) and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { + if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { if ( $this->{'Function'} == 'None' || $this->{'Function'} == 'Monitor' || $mode == 'stop' ) { if ( ZM_OPT_CONTROL ) { daemonControl('stop', 'zmtrack.pl', '-m '.$this->{'Id'}); @@ -367,8 +367,8 @@ private $status_fields = array( } } - if ( !array_key_exists('GroupIds', $this) ) { - if ( array_key_exists('Id', $this) and $this->{'Id'} ) { + if ( !property_exists($this, 'GroupIds') ) { + if ( property_exists($this, 'Id') and $this->{'Id'} ) { $this->{'GroupIds'} = dbFetchAll('SELECT `GroupId` FROM `Groups_Monitors` WHERE `MonitorId`=?', 'GroupId', array($this->{'Id'}) ); if ( ! $this->{'GroupIds'} ) $this->{'GroupIds'} = array(); @@ -417,7 +417,7 @@ private $status_fields = array( if ( $new ) { $this->{'Storage'} = $new; } - if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) { + if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) { $this->{'Storage'} = isset($this->{'StorageId'}) ? Storage::find_one(array('Id'=>$this->{'StorageId'})) : new Storage(NULL); @@ -493,7 +493,7 @@ public function sendControlCommand($command) { } } - if ( (!defined('ZM_SERVER_ID')) or ( array_key_exists('ServerId', $this) and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { + if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { # Local Logger::Debug('Trying to send options ' . print_r($options, true)); diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php index ca6b17ef7..f67f3ace5 100644 --- a/web/includes/MontageLayout.php +++ b/web/includes/MontageLayout.php @@ -1,133 +1,22 @@ null, 'Name' => '', 'Positions' => 0, ); - public function __construct( $IdOrRow = NULL ) { - if ( $IdOrRow ) { - $row = NULL; - if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) { - $row = dbFetchOne( 'SELECT * FROM MontageLayouts WHERE Id=?', NULL, array( $IdOrRow ) ); - if ( ! $row ) { - Error("Unable to load MontageLayout record for Id=" . $IdOrRow ); - } - } else if ( is_array( $IdOrRow ) ) { - $row = $IdOrRow; - } else { - Error("Unknown argument passed to MontageLayout Constructor ($IdOrRow)"); - return; - } - - if ( $row ) { - foreach ($row as $k => $v) { - $this->{$k} = $v; - } - } else { - Error('No row for MontageLayout ' . $IdOrRow ); - } - } # end if isset($IdOrRow) - } // end function __construct - - public function __call($fn, array $args){ - if ( count($args) ) { - $this->{$fn} = $args[0]; - } - if ( array_key_exists($fn, $this) ) { - return $this->{$fn}; - } else { - if ( array_key_exists( $fn, $this->defaults ) ) { - return $this->defaults{$fn}; - } else { - $backTrace = debug_backtrace(); - $file = $backTrace[1]['file']; - $line = $backTrace[1]['line']; - Warning( "Unknown function call MontageLayout->$fn from $file:$line" ); - } - } + public static function find( $parameters = array(), $options = array() ) { + return ZM_Object::_find(get_class(), $parameters, $options); } - public function set( $data ) { - foreach ($data as $k => $v) { - if ( is_array( $v ) ) { - # perhaps should turn into a comma-separated string - $this->{$k} = implode(',',$v); - } else if ( is_string( $v ) ) { - $this->{$k} = trim( $v ); - } else if ( is_integer( $v ) ) { - $this->{$k} = $v; - } else if ( is_bool( $v ) ) { - $this->{$k} = $v; - } else { - Error( "Unknown type $k => $v of var " . gettype( $v ) ); - $this->{$k} = $v; - } - } + public static function find_one( $parameters = array(), $options = array() ) { + return ZM_Object::_find_one(get_class(), $parameters, $options); } - public static function find( $parameters = null, $options = null ) { - $filters = array(); - $sql = 'SELECT * FROM MontageLayouts '; - $values = array(); - - if ( $parameters ) { - $fields = array(); - $sql .= 'WHERE '; - foreach ( $parameters as $field => $value ) { - if ( $value == null ) { - $fields[] = $field.' IS NULL'; - } else if ( is_array( $value ) ) { - $func = function(){return '?';}; - $fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')'; - $values += $value; - - } else { - $fields[] = $field.'=?'; - $values[] = $value; - } - } - $sql .= implode(' AND ', $fields ); - } - if ( $options and isset($options['order']) ) { - $sql .= ' ORDER BY ' . $options['order']; - } - $result = dbQuery($sql, $values); - if ( $result ) { - $results = $result->fetchALL(); - foreach ( $results as $row ) { - $filters[] = new MontageLayout($row); - } - } - return $filters; - } - public function save( $new_values = null ) { - if ( $new_values ) { - foreach ( $new_values as $k=>$v ) { - $this->{$k} = $v; - } - } - - $fields = array_values( array_filter( array_keys($this->defaults), function($field){return $field != 'Id';} ) ); - $values = null; - if ( isset($this->{'Id'}) ) { - $sql = 'UPDATE MontageLayouts SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?'; - $values = array_map( function($field){return $this->{$field};}, $fields ); - $values[] = $this->{'Id'}; - dbQuery($sql, $values); - } else { - $sql = 'INSERT INTO MontageLayouts ('.implode( ',', $fields ).') VALUES ('.implode(',',array_map( function(){return '?';}, $fields ) ).')'; - $values = array_map( function($field){return $this->{$field};}, $fields ); - dbQuery($sql, $values); - global $dbConn; - $this->{'Id'} = $dbConn->lastInsertId(); - } - } // end function save } // end class MontageLayout ?> diff --git a/web/includes/Object.php b/web/includes/Object.php index d51cf082d..6a82ec37f 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -45,7 +45,7 @@ class ZM_Object { $this->{$fn} = $args[0]; } - if ( array_key_exists($fn, $this) ) { + if ( property_exists($this, $fn) ) { return $this->{$fn}; } else { if ( array_key_exists($fn, $this->defaults) ) { @@ -140,10 +140,10 @@ class ZM_Object { foreach ($this->defaults as $key => $value) { if ( is_callable(array($this, $key)) ) { $json[$key] = $this->$key(); - } else if ( array_key_exists($key, $this) ) { + } else if ( property_exists($this, $key) ) { $json[$key] = $this->{$key}; } else { - $json[$key] = $this->defaults{$key}; + $json[$key] = $this->defaults[$key]; } } return json_encode($json); @@ -215,7 +215,7 @@ class ZM_Object { } else if ( $this->$field() != $value ) { $changes[$field] = $value; } - } else if ( array_key_exists($field, $this) ) { + } else if ( property_exists($this, $field) ) { $type = (array_key_exists($field, $this->defaults) && is_array($this->defaults[$field])) ? $this->defaults[$field]['type'] : 'scalar'; Logger::Debug("Checking field $field => current ". (is_array($this->{$field}) ? implode(',',$this->{$field}) : $this->{$field}) . ' ?= ' . diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 01465de65..286cec8da 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -80,7 +80,7 @@ class Storage extends ZM_Object { } public function disk_total_space() { - if ( !array_key_exists('disk_total_space', $this) ) { + if ( !property_exists($this, 'disk_total_space') ) { $path = $this->Path(); if ( file_exists($path) ) { $this->{'disk_total_space'} = disk_total_space($path); @@ -94,7 +94,7 @@ class Storage extends ZM_Object { public function disk_used_space() { # This isn't a function like this in php, so we have to add up the space used in each event. - if ( ( !array_key_exists('disk_used_space', $this)) or !$this->{'disk_used_space'} ) { + if ( ( !property_exists($this, 'disk_used_space')) or !$this->{'disk_used_space'} ) { if ( $this->{'Type'} == 's3fs' ) { $this->{'disk_used_space'} = $this->event_disk_space(); } else { @@ -112,7 +112,7 @@ class Storage extends ZM_Object { public function event_disk_space() { # This isn't a function like this in php, so we have to add up the space used in each event. - if ( (! array_key_exists('DiskSpace', $this)) or (!$this->{'DiskSpace'}) ) { + if ( (! property_exists($this, 'DiskSpace')) or (!$this->{'DiskSpace'}) ) { $used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id())); do { @@ -130,8 +130,8 @@ class Storage extends ZM_Object { } // end function event_disk_space public function Server() { - if ( ! array_key_exists('Server',$this) ) { - if ( array_key_exists('ServerId', $this) ) { + if ( ! property_exists($this, 'Server') ) { + if ( property_exists($this, 'ServerId') ) { $this->{'Server'} = Server::find_one(array('Id'=>$this->{'ServerId'})); if ( !$this->{'Server'} ) { diff --git a/web/includes/database.php b/web/includes/database.php index eab70f47f..5cd900be0 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -110,16 +110,10 @@ function dbError($sql) { function dbEscape( $string ) { global $dbConn; - if ( version_compare(phpversion(), '4.3.0', '<')) - if ( get_magic_quotes_gpc() ) - return $dbConn->quote(stripslashes($string)); - else - return $dbConn->quote($string); + if ( version_compare(phpversion(), '5.4', '<=') and get_magic_quotes_gpc() ) + return $dbConn->quote(stripslashes($string)); else - if ( get_magic_quotes_gpc() ) - return $dbConn->quote(stripslashes($string)); - else - return $dbConn->quote($string); + return $dbConn->quote($string); } function dbQuery($sql, $params=NULL) { From 0de6396a5b41d37c724e43a1a14380f070392045 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 7 Dec 2019 12:39:28 -0500 Subject: [PATCH 04/82] Test for null in user before testing for access in CanEdit et all --- web/includes/auth.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/includes/auth.php b/web/includes/auth.php index 4fc39d30e..f958463c3 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -220,19 +220,19 @@ function generateAuthHash($useRemoteAddr, $force=false) { function visibleMonitor($mid) { global $user; - return ( empty($user['MonitorIds']) || in_array($mid, explode(',', $user['MonitorIds'])) ); + return ( $user && empty($user['MonitorIds']) || in_array($mid, explode(',', $user['MonitorIds'])) ); } function canView($area, $mid=false) { global $user; - return ( ($user[$area] == 'View' || $user[$area] == 'Edit') && ( !$mid || visibleMonitor($mid) ) ); + return ( $user && ($user[$area] == 'View' || $user[$area] == 'Edit') && ( !$mid || visibleMonitor($mid) ) ); } function canEdit($area, $mid=false) { global $user; - return ( $user[$area] == 'Edit' && ( !$mid || visibleMonitor($mid) )); + return ( $user && ($user[$area] == 'Edit') && ( !$mid || visibleMonitor($mid) )); } function userFromSession() { From 86fc8526219a3dad78465543f5818ddb2f78212d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 8 Dec 2019 10:59:50 -0500 Subject: [PATCH 05/82] bump version in zoneminder.spec --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index e319f4c8f..e49b3dd16 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -23,7 +23,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.33.14 +Version: 1.33.15 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons From 2aef547f374a6ab4103c4d5ef7caf2e7a0fa1b60 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 8 Dec 2019 11:01:46 -0500 Subject: [PATCH 06/82] add changelog about bump to 1.33.15 --- distros/redhat/zoneminder.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index e49b3dd16..2773a4ad0 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -411,6 +411,9 @@ EOF %dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %changelog +* Sun Dec 08 2019 Isaac Connor - 1.33.15-1 +- Bump to 1.33.15 Development + * Sun Aug 11 2019 Andrew Bauer - 1.33.14-1 - Bump to 1.33.13 Development From ed417a49b4a3892abbceb11100bae4add0c32737 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 8 Dec 2019 11:21:38 -0500 Subject: [PATCH 07/82] increase logspopup width to eliminate scrollbars --- web/skins/classic/js/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/js/base.js b/web/skins/classic/js/base.js index 24f5d9a22..4ecc4c234 100644 --- a/web/skins/classic/js/base.js +++ b/web/skins/classic/js/base.js @@ -46,7 +46,7 @@ var popupSizes = { 'group': {'width': 760, 'height': 600}, 'groups': {'width': 540, 'height': 420}, 'image': {'addWidth': 48, 'addHeight': 80}, - 'log': {'width': 1080, 'height': 720}, + 'log': {'width': 1180, 'height': 720}, 'login': {'width': 720, 'height': 480}, 'logout': {'width': 260, 'height': 150}, 'monitor': {'width': 800, 'height': 780}, From 3bd0525e6445c22a3c661b6801482ca0e778c213 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 8 Dec 2019 14:27:07 -0500 Subject: [PATCH 08/82] escape column names for mysql8 --- web/includes/actions/function.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/actions/function.php b/web/includes/actions/function.php index ebdc416fc..00e4e21f7 100644 --- a/web/includes/actions/function.php +++ b/web/includes/actions/function.php @@ -39,7 +39,7 @@ if ( $action == 'function' ) { $oldFunction = $monitor['Function']; $oldEnabled = $monitor['Enabled']; if ( $newFunction != $oldFunction || $newEnabled != $oldEnabled ) { - dbQuery('UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?', + dbQuery('UPDATE Monitors SET `Function`=?, `Enabled`=? WHERE `Id`=?', array($newFunction, $newEnabled, $mid)); $monitor['Function'] = $newFunction; From ea89ebf15087fec2c83a7fe736db1be34006b971 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 8 Dec 2019 21:33:29 -0500 Subject: [PATCH 09/82] more mysql8 fixes --- web/includes/actions/state.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/includes/actions/state.php b/web/includes/actions/state.php index 9799cdec3..0f7a9e9a5 100644 --- a/web/includes/actions/state.php +++ b/web/includes/actions/state.php @@ -31,19 +31,19 @@ if ( $action == 'state' ) { } } else if ( $action == 'save' ) { if ( !empty($_REQUEST['runState']) || !empty($_REQUEST['newState']) ) { - $sql = 'SELECT Id,Function,Enabled FROM Monitors ORDER BY Id'; + $sql = 'SELECT `Id`,`Function`,`Enabled` FROM Monitors ORDER BY Id'; $definitions = array(); - foreach( dbFetchAll($sql) as $monitor ) { + foreach ( dbFetchAll($sql) as $monitor ) { $definitions[] = $monitor['Id'].':'.$monitor['Function'].':'.$monitor['Enabled']; } $definition = join(',', $definitions); if ( $_REQUEST['newState'] ) $_REQUEST['runState'] = $_REQUEST['newState']; - dbQuery('REPLACE INTO States SET Name=?, Definition=?', array($_REQUEST['runState'],$definition)); + dbQuery('REPLACE INTO `States` SET `Name`=?, `Definition`=?', array($_REQUEST['runState'],$definition)); } } else if ( $action == 'delete' ) { if ( isset($_REQUEST['runState']) ) - dbQuery('DELETE FROM States WHERE Name=?', array($_REQUEST['runState'])); + dbQuery('DELETE FROM `States` WHERE `Name`=?', array($_REQUEST['runState'])); } $view = 'console'; ?> From c6813fecd5bc7172a158f35a93c93c620cbc98f3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Dec 2019 10:14:32 -0500 Subject: [PATCH 10/82] handle new values for Orientation enum. Spacing, quotes. Handle uppercase HTTP in ControlAddress. --- .../lib/ZoneMinder/Control/SkyIPCam7xx.pm | 112 ++++++++---------- 1 file changed, 51 insertions(+), 61 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm index 7175d1e84..ebbaf3a8a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm @@ -1,6 +1,6 @@ # ========================================================================== # -# ZoneMinder Airlink SkyIPCam AICN747/AICN747W Control Protocol Module, $Date: 2008-09-13 17:30:29 +0000 (Sat, 13 Sept 2008) $, $Revision: 2229 $ +# ZoneMinder Airlink SkyIPCam AICN747/AICN747W Control Protocol Module # Copyright (C) 2008 Brian Rudy (brudyNO@SPAMpraecogito.com) # # This program is free software; you can redistribute it and/or @@ -43,8 +43,6 @@ our @ISA = qw(ZoneMinder::Control); use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); -use Time::HiRes qw( usleep ); - sub open { my $self = shift; @@ -52,58 +50,50 @@ sub open { use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); + $self->{ua}->agent('ZoneMinder Control Agent/'.ZoneMinder::Base::ZM_VERSION); $self->{state} = 'open'; } -sub printMsg { - my $self = shift; - my $msg = shift; - my $msg_len = length($msg); - - Debug( $msg."[".$msg_len."]" ); -} - sub sendCmd { my $self = shift; my $cmd = shift; my $result = undef; - printMsg( $cmd, "Tx" ); + $self->printMsg($cmd, 'Tx'); my $url; - if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) { + if ( $self->{Monitor}->{ControlAddress} =~ /^http/i ) { $url = $self->{Monitor}->{ControlAddress}.$cmd; } else { $url = 'http://'.$self->{Monitor}->{ControlAddress}.$cmd; - } # en dif - my $req = HTTP::Request->new( GET=>$url ); + } # end if + my $req = HTTP::Request->new(GET=>$url); my $res = $self->{ua}->request($req); if ( $res->is_success ) { $result = !undef; } else { - Error( "Error check failed: '".$res->status_line()."'" ); + Error('Error check failed: \''.$res->status_line().'\''); } - return( $result ); + return $result; } sub reset { my $self = shift; - Debug( "Camera Reset" ); - my $cmd = "/admin/ptctl.cgi?move=reset"; - $self->sendCmd( $cmd ); + Debug('Camera Reset'); + my $cmd = '/admin/ptctl.cgi?move=reset'; + $self->sendCmd($cmd); } sub moveMap { my $self = shift; my $params = shift; - my $xcoord = $self->getParam( $params, 'xcoord' ); - my $ycoord = $self->getParam( $params, 'ycoord' ); + my $xcoord = $self->getParam($params, 'xcoord'); + my $ycoord = $self->getParam($params, 'ycoord'); my $hor = $xcoord * 100 / $self->{Monitor}->{Width}; my $ver = $ycoord * 100 / $self->{Monitor}->{Height}; @@ -125,81 +115,81 @@ sub moveMap { elsif ( $hor > 50 ) { # right $horSteps = (($hor - 50) / 50) * $maxhor; - $horDir = "right"; + $horDir = 'right'; } # Vertical movement if ( $ver < 50 ) { # up $verSteps = ((50 - $ver) / 50) * $maxver; - $verDir = "up"; + $verDir = 'up'; } elsif ( $ver > 50 ) { # down $verSteps = (($ver - 50) / 50) * $maxver; - $verDir = "down"; + $verDir = 'down'; } my $v = int($verSteps); my $h = int($horSteps); - Debug( "Move Map to $xcoord,$ycoord, hor=$h $horDir, ver=$v $verDir"); + Debug("Move Map to $xcoord,$ycoord, hor=$h $horDir, ver=$v $verDir"); my $cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$horDir&Degree=$h"; - $self->sendCmd( $cmd ); + $self->sendCmd($cmd); $cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$verDir&Degree=$v"; - $self->sendCmd( $cmd ); + $self->sendCmd($cmd); } sub moveRelUp { my $self = shift; my $params = shift; - my $step = $self->getParam( $params, 'tiltstep' ); - Debug( "Step Up $step" ); - my $cmd = "/admin/ptctl.cgi?move=up"; - $self->sendCmd( $cmd ); + my $step = $self->getParam($params, 'tiltstep'); + Debug("Step Up $step"); + my $cmd = '/admin/ptctl.cgi?move=up'; + $self->sendCmd($cmd); } sub moveRelDown { my $self = shift; my $params = shift; - my $step = $self->getParam( $params, 'tiltstep' ); - Debug( "Step Down $step" ); - my $cmd = "/admin/ptctl.cgi?move=down"; - $self->sendCmd( $cmd ); + my $step = $self->getParam($params, 'tiltstep'); + Debug("Step Down $step"); + my $cmd = '/admin/ptctl.cgi?move=down'; + $self->sendCmd($cmd); } sub moveRelLeft { my $self = shift; my $params = shift; - my $step = $self->getParam( $params, 'panstep' ); + my $step = $self->getParam($params, 'panstep'); - if ( $self->{Monitor}->{Orientation} eq "hori" ) { - Debug( "Stepping Right because flipped horizontally " ); - $self->sendCmd( "/admin/ptctl.cgi?move=right" ); + if ( $self->{Monitor}->{Orientation} eq 'FLIP_HORI' ) { + Debug('Stepping Right because flipped horizontally'); + $self->sendCmd('/admin/ptctl.cgi?move=right'); } else { - Debug( "Step Left" ); - $self->sendCmd( "/admin/ptctl.cgi?move=left" ); + Debug('Step Left'); + $self->sendCmd('/admin/ptctl.cgi?move=left'); } } sub moveRelRight { my $self = shift; my $params = shift; - my $step = $self->getParam( $params, 'panstep' ); - if ( $self->{Monitor}->{Orientation} eq "hori" ) { - Debug( "Stepping Left because flipped horizontally " ); - $self->sendCmd( "/admin/ptctl.cgi?move=left" ); + my $step = $self->getParam($params, 'panstep'); + if ( $self->{Monitor}->{Orientation} eq 'FLIP_HORI' ) { + Debug('Stepping Left because flipped horizontally'); + $self->sendCmd('/admin/ptctl.cgi?move=left'); } else { - Debug( "Step Right" ); - $self->sendCmd( "/admin/ptctl.cgi?move=right" ); + Debug('Step Right'); + $self->sendCmd('/admin/ptctl.cgi?move=right'); } } sub presetClear { my $self = shift; my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Clear Preset $preset" ); + my $preset = $self->getParam($params, 'preset'); + Debug("Clear Preset $preset"); #my $cmd = "/axis-cgi/com/ptz.cgi?removeserverpresetno=$preset"; #$self->sendCmd( $cmd ); } @@ -207,26 +197,26 @@ sub presetClear { sub presetSet { my $self = shift; my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Set Preset $preset" ); - my $cmd = "/admin/ptctl.cgi?position=" . ($preset - 1) . "&positionname=zm$preset"; + my $preset = $self->getParam($params, 'preset'); + Debug("Set Preset $preset"); + my $cmd = '/admin/ptctl.cgi?position=' . ($preset - 1) . "&positionname=zm$preset"; $self->sendCmd( $cmd ); } sub presetGoto { my $self = shift; my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Goto Preset $preset" ); - my $cmd = "/admin/ptctl.cgi?move=p" . ($preset - 1); - $self->sendCmd( $cmd ); + my $preset = $self->getParam($params, 'preset'); + Debug("Goto Preset $preset"); + my $cmd = '/admin/ptctl.cgi?move=p'.($preset - 1); + $self->sendCmd($cmd); } sub presetHome { my $self = shift; - Debug( "Home Preset" ); - my $cmd = "/admin/ptctl.cgi?move=h"; - $self->sendCmd( $cmd ); + Debug('Home Preset'); + my $cmd = '/admin/ptctl.cgi?move=h'; + $self->sendCmd($cmd); } 1; From bedc61a34765ce596ae7c85edf87a8359507c7c0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 11:49:55 -0500 Subject: [PATCH 11/82] handle dbFetchNext on null result more gracefully --- web/includes/database.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/includes/database.php b/web/includes/database.php index eab70f47f..0cb674a0a 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -212,6 +212,10 @@ function dbFetch($sql, $col=false) { } function dbFetchNext($result, $col=false) { + if ( !$result ) { + ZM\Error("dbFetchNext called on null result."); + return false; + } if ( $dbRow = $result->fetch(PDO::FETCH_ASSOC) ) return $col ? $dbRow[$col] : $dbRow; return false; From d2a23e4822994bded5cea96ad1421e92f51e157e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 11:50:11 -0500 Subject: [PATCH 12/82] add possing port to Monitor->UrlToIndex --- web/includes/Monitor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index a9be54405..3814a3944 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -467,8 +467,8 @@ private $status_fields = array( return $source; } // end function Source - public function UrlToIndex() { - return $this->Server()->UrlToIndex(); + public function UrlToIndex($port=null) { + return $this->Server()->UrlToIndex($port); //ZM_MIN_STREAMING_PORT ? (ZM_MIN_STREAMING_PORT+$this->Id()) : null); } From 0bbbbb302e8fa29763726b48b18ca51006aa8c56 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 11:51:07 -0500 Subject: [PATCH 13/82] add default for Units in new zone --- web/skins/classic/views/zone.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index e72eb43cf..6b5801744 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -69,6 +69,7 @@ if ( !isset($newZone) ) { 'Id' => 0, 'Name' => translate('New'), 'Type' => 'Active', + 'Units' => 'Pixels', 'MonitorId' => $monitor->Id(), 'NumCoords' => 4, 'Coords' => sprintf('%d,%d %d,%d, %d,%d %d,%d', $minX, $minY, $maxX, $minY, $maxX, $maxY, $minX, $maxY), From 0dbc1ef15c3ca31a5c0f85c8221b680699db59e4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 11:51:55 -0500 Subject: [PATCH 14/82] Use multiport when talking monitor stream on montage --- web/skins/classic/views/js/montage.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index f2dea53bf..c39d7311d 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -35,7 +35,7 @@ monitorData[monitorData.length] = { 'connKey': connKey() ?>, 'width': ViewWidth() ?>, 'height':ViewHeight() ?>, - 'url': 'UrlToIndex() ?>', + 'url': 'UrlToIndex( $monitor->Id() + ZM_MIN_STREAMING_PORT) ?>', 'onclick': function(){createPopup( '?view=watch&mid=Id() ?>', 'zmWatchId() ?>', 'watch', ViewWidth(), $monitor->PopupScale() ); ?>, ViewHeight(), $monitor->PopupScale() ); ?> );}, 'type': 'Type() ?>', 'refresh': 'Refresh() ?>' From b24e912050ccf24cede190fe368ab19b34dcca99 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 17:46:56 -0500 Subject: [PATCH 15/82] Use ZM\Server::find_one for loading server so that it gets cached. Use a single regexp to determine config line validity instead of two for efficiency --- web/includes/config.php.in | 57 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/web/includes/config.php.in b/web/includes/config.php.in index dd3439680..ef1bf4a16 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -33,9 +33,9 @@ $configFile = ZM_CONFIG; $localConfigFile = basename($configFile); if ( file_exists( $localConfigFile ) && filesize( $localConfigFile ) > 0 ) { if ( php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']) ) - print( "Warning, overriding installed $localConfigFile file with local copy\n" ); + print("Warning, overriding installed $localConfigFile file with local copy\n"); else - error_log( "Warning, overriding installed $localConfigFile file with local copy" ); + error_log("Warning, overriding installed $localConfigFile file with local copy"); $configFile = $localConfigFile; } @@ -49,19 +49,19 @@ if ( is_dir($configSubFolder) ) { if ( is_readable($configSubFolder) ) { foreach ( glob("$configSubFolder/*.conf") as $filename ) { //error_log("processing $filename"); - $configvals = array_replace($configvals, process_configfile($filename) ); + $configvals = array_replace($configvals, process_configfile($filename)); } } else { - error_log( "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder." ); + error_log("WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder."); } } else { - error_log( "WARNING: ZoneMinder configuration subfolder found but is not a directory. Check $configSubFolder." ); + error_log("WARNING: ZoneMinder configuration subfolder found but is not a directory. Check $configSubFolder."); } # Now that our array our finalized, define each key => value # pair in the array as a constant -foreach( $configvals as $key => $value) { - define( $key, $value ); +foreach ( $configvals as $key => $value ) { + define($key, $value); } // @@ -135,8 +135,8 @@ define( 'SCALE_BASE', 100 ); // The additional scalin define( 'STRF_FMT_DATETIME_DB', '%Y-%m-%d %H:%M:%S' ); // Strftime format for database queries, don't change define( 'MYSQL_FMT_DATETIME_SHORT', '%y/%m/%d %H:%i:%S' ); // MySQL date_format shorter format for dates with time -require_once( 'database.php' ); -require_once( 'logger.php' ); +require_once('database.php'); +require_once('logger.php'); loadConfig(); ZM\Logger::fetch()->initialise(); @@ -165,28 +165,30 @@ function loadConfig( $defineConsts=true ) { $result = $dbConn->query('SELECT Name,Value FROM Config'); if ( !$result ) echo mysql_error(); - while( $row = dbFetchNext( $result ) ) { + while( $row = dbFetchNext($result) ) { if ( $defineConsts ) - define( $row['Name'], $row['Value'] ); + define($row['Name'], $row['Value']); $config[$row['Name']] = $row; } } # end function loadConfig // For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID if ( ! defined('ZM_SERVER_ID') ) { + require_once('Server.php'); if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) { - $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME)); - if ( ! $server_id ) { + # Use Server lookup so that it caches + $Server = ZM\Server::find_one(array('Name'=>ZM_SERVER_NAME)); + if ( !$Server ) { Error('Invalid Multi-Server configration detected. ZM_SERVER_NAME set to ' . ZM_SERVER_NAME . ' in zm.conf, but no corresponding entry found in Servers table.'); } else { - define( 'ZM_SERVER_ID', $server_id ); + define('ZM_SERVER_ID', $Server->Id()); } } else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) { - $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_HOST)); - if ( ! $server_id ) { + $Server = ZM\Server::find_one(array('Name'=>ZM_SERVER_HOST)); + if ( ! $Server ) { Error('Invalid Multi-Server configration detected. ZM_SERVER_HOST set to ' . ZM_SERVER_HOST . ' in zm.conf, but no corresponding entry found in Servers table.'); } else { - define( 'ZM_SERVER_ID', $server_id ); + define('ZM_SERVER_ID', $Server->Id()); } } } @@ -197,21 +199,22 @@ function process_configfile($configFile) { if ( is_readable( $configFile ) ) { $configvals = array(); - $cfg = fopen( $configFile, 'r') or Error("Could not open config file: $configFile."); + $cfg = fopen($configFile, 'r') or Error("Could not open config file: $configFile."); while ( !feof($cfg) ) { - $str = fgets( $cfg, 256 ); - if ( preg_match( '/^\s*$/', $str )) + $str = fgets($cfg, 256); + if ( preg_match('/^\s*(#.*)?$/', $str) ) { continue; - elseif ( preg_match( '/^\s*#/', $str )) - continue; - elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*[\'"]*(.*?)[\'"]*\s*$/', $str, $matches )) + } else if ( preg_match( '/^\s*([^=\s]+)\s*=\s*[\'"]*(.*?)[\'"]*\s*$/', $str, $matches )) { $configvals[$matches[1]] = $matches[2]; + } else { + Error("Malformed line in config $configFile\n$str"); + } } - fclose( $cfg ); - return( $configvals ); + fclose($cfg); + return $configvals; } else { - error_log( "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile." ); - return( false ); + error_log("WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile."); + return false; } } From 5fcd6361bc2e6ecf3b7ac4f80f200c4fb13bf26c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 17:47:18 -0500 Subject: [PATCH 16/82] fix segfault reading frames for .mp4 in zms --- src/zm_ffmpeg_input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index ab7cbe8d3..bed9f9fed 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -138,7 +138,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { frame = zm_av_frame_alloc(); } ret = zm_send_packet_receive_frame(context, frame, packet); - if ( ret <= 0 ) { + if ( ret < 0 ) { Error("Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str()); zm_av_packet_unref(&packet); From 18ed90d1477cc800d2a5c4b11e73c46428cc4b7e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 17:47:51 -0500 Subject: [PATCH 17/82] remove second hit to db to load storage areas with no serverid --- web/skins/classic/includes/functions.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 5abd519cf..60558f8e8 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -389,8 +389,8 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
  • trending_up :
  • storage 90 ? ' class="warning"' : '' ).'>'.translate('DB').':'.$connections.'/'.$max_connections.''; ?> @@ -398,8 +398,12 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) { Path()] = $area; + if ( ! $area->ServerId() ) { + $storage_areas_with_no_server_id[] = $area; + } } $func = function($S){ $class = ''; @@ -415,9 +419,9 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) { '; }; #$func = function($S){ return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; }; if ( count($storage_areas) > 4 ) - $storage_areas = ZM\Storage::find( array('ServerId'=>null) ); + $storage_areas = $storage_areas_with_no_server_id; if ( count($storage_areas) <= 4 ) - echo implode( ', ', array_map ( $func, $storage_areas ) ); + echo implode(', ', array_map($func, $storage_areas)); echo ' ' . ZM_PATH_MAP .': '. getDiskPercent(ZM_PATH_MAP).'%'; ?> From 5b7efb2b3392c144d1d4f148ab38331a0019089f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 17:48:22 -0500 Subject: [PATCH 18/82] fix mouseover streaming in chrome when adblocker disabled --- web/skins/classic/views/js/events.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index ca7f7c7ec..e32281c81 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -146,10 +146,12 @@ if ( openFilterWindow ) { function thumbnail_onmouseover(event) { var img = event.target; + img.src = ''; img.src = img.getAttribute('stream_src'); } function thumbnail_onmouseout(event) { var img = event.target; + img.src = ''; img.src = img.getAttribute('still_src'); } From 16a73d6d5a3212706e5fd7c2e944ddbea7fcc99c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Dec 2019 18:12:33 -0500 Subject: [PATCH 19/82] don't seek back when not neccesary --- src/zm_ffmpeg_input.cpp | 21 ++++++++++++++++++--- src/zm_ffmpeg_input.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index bed9f9fed..352de347c 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -10,6 +10,7 @@ FFmpeg_Input::FFmpeg_Input() { FFMPEGInit(); streams = NULL; frame = NULL; + last_seek_request = -1; } FFmpeg_Input::~FFmpeg_Input() { @@ -102,7 +103,6 @@ int FFmpeg_Input::Open(const char *filepath) { } // end int FFmpeg_Input::Open( const char * filepath ) AVFrame *FFmpeg_Input::get_frame(int stream_id) { - Debug(1, "Getting frame from stream %d", stream_id); int frameComplete = false; AVPacket packet; @@ -144,6 +144,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { zm_av_packet_unref(&packet); av_frame_free(&frame); continue; + } else { + zm_dump_frame(frame, "resulting frame"); } frameComplete = 1; @@ -175,9 +177,20 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { } // Have to grab a frame to update our current frame to know where we are get_frame(stream_id); - } // end if ! frame + } // end if ! frame - if ( frame->pts > seek_target ) { + if ( !frame ) { + Warning("Unable to get frame."); + return NULL; + } + + if ( + (last_seek_request >= 0) + && + (last_seek_request > seek_target ) + && + (frame->pts > seek_target) + ) { zm_dump_frame(frame, "frame->pts > seek_target, seek backwards"); // our frame must be beyond our seek target. so go backwards to before it if ( ( ret = av_seek_frame(input_format_context, stream_id, seek_target, @@ -191,6 +204,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { zm_dump_frame(frame, "frame->pts > seek_target, got"); } // end if frame->pts > seek_target + last_seek_request = seek_target; + // Seeking seems to typically seek to a keyframe, so then we have to decode until we get the frame we want. if ( frame->pts <= seek_target ) { zm_dump_frame(frame, "pts <= seek_target"); diff --git a/src/zm_ffmpeg_input.h b/src/zm_ffmpeg_input.h index 2f524ac45..900f14d4a 100644 --- a/src/zm_ffmpeg_input.h +++ b/src/zm_ffmpeg_input.h @@ -42,6 +42,7 @@ class FFmpeg_Input { int audio_stream_id; AVFormatContext *input_format_context; AVFrame *frame; + int64_t last_seek_request; }; #endif From 4d9d4ba9573c084661f8895d26711b0964457cb9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 15 Dec 2019 10:35:43 -0500 Subject: [PATCH 20/82] Do not allow deletion of archived events. --- web/includes/functions.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index aea0c8b14..93e30fb85 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -409,6 +409,11 @@ ZM\Logger::Debug("Event type: " . gettype($event)); global $user; + if ( $event->Archived() ) { + ZM\Info('Cannot delete Archived event.'); + return; + } # end if Archived + if ( $user['Events'] == 'Edit' ) { $event->delete(); } # CAN EDIT From 5f006421cc2fe86112bd4bc2b81f713cb3a4398e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 15 Dec 2019 15:31:40 -0500 Subject: [PATCH 21/82] fix #2771. Correct relationship from hasMany to hasAndBelongsToMany for Monitors in Group Modelel. Use save Assiociated in Controller, and add code to handle backwards compatibility by turning MonitorIds into the appropriate Monitor array --- web/api/app/Controller/GroupsController.php | 18 +++++++++++++----- web/api/app/Model/Group.php | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/web/api/app/Controller/GroupsController.php b/web/api/app/Controller/GroupsController.php index 6f0a88300..5d19b5d98 100644 --- a/web/api/app/Controller/GroupsController.php +++ b/web/api/app/Controller/GroupsController.php @@ -77,16 +77,24 @@ class GroupsController extends AppController { } $this->Group->create(); - if ( $this->Group->save($this->request->data) ) { + + if ( $this->request->data['Group']['MonitorIds'] and ! isset($this->request->data['Monitor']) ) { + $this->request->data['Monitor'] = explode(',', $this->request->data['Group']['MonitorIds']); + unset($this->request->data['Group']['MonitorIds']); + } + if ( $this->Group->saveAssociated($this->request->data, array('atomic'=>true)) ) { return $this->flash( __('The group has been saved.'), array('action' => 'index') ); - } - } - $monitors = $this->Group->Monitor->find('list'); + } else { + ZM\Error("Failed to save Group"); + debug($this->Group->invalidFields()); + } + } # end if post + $monitors = $this->Group->Monitor->find('list'); $this->set(compact('monitors')); - } + } # end add /** * edit method diff --git a/web/api/app/Model/Group.php b/web/api/app/Model/Group.php index 108f9b9c7..8d8f533ca 100644 --- a/web/api/app/Model/Group.php +++ b/web/api/app/Model/Group.php @@ -59,7 +59,7 @@ class Group extends AppModel { * * @var array */ - public $hasMany = array( + public $hasAndBelongsToMany = array( 'Monitor' => array( 'className' => 'Monitor', 'joinTable' => 'Groups_Monitors', From 3b12b67b4a4a604be7f6adbe4b203853974b19e3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Dec 2019 10:40:51 -0500 Subject: [PATCH 22/82] fix eslint --- web/skins/classic/views/js/export.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/export.js b/web/skins/classic/views/js/export.js index 73e81ab4a..d553f9385 100644 --- a/web/skins/classic/views/js/export.js +++ b/web/skins/classic/views/js/export.js @@ -4,7 +4,7 @@ function configureExportButton(element) { var form = element.form; var eventCount = 0; - document.querySelectorAll('input[name="eids[]"]').forEach(function(el){ + document.querySelectorAll('input[name="eids[]"]').forEach(function(el) { if ( el.checked ) { eventCount ++; } @@ -43,7 +43,6 @@ function exportProgress() { } function exportResponse(respObj, respText) { - clearInterval(exportTimer); if ( respObj.result != 'Ok' ) { $('exportProgressTicker').set('text', respObj.message); From 34354f587177600cf0427299a12a4b3633795018 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Dec 2019 12:13:00 -0500 Subject: [PATCH 23/82] Add Notes field to monitors to store random info in. Bump version to 1.33.16. use htmlSElect for savejpegs. Move storage area under Storage tab. --- db/zm_create.sql.in | 1 + db/zm_update-1.33.16.sql | 12 ++ distros/redhat/zoneminder.spec | 2 +- version | 2 +- web/includes/Monitor.php | 211 ++++++++++--------- web/skins/classic/css/base/views/monitor.css | 4 + web/skins/classic/views/monitor.php | 56 +++-- 7 files changed, 158 insertions(+), 130 deletions(-) create mode 100644 db/zm_update-1.33.16.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 44eb1a048..d4efb5317 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -434,6 +434,7 @@ DROP TABLE IF EXISTS `Monitors`; CREATE TABLE `Monitors` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', + `Notes` TEXT NOT NULL default '', `ServerId` int(10) unsigned, `StorageId` smallint(5) unsigned default 0, `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', diff --git a/db/zm_update-1.33.16.sql b/db/zm_update-1.33.16.sql new file mode 100644 index 000000000..aacfd9425 --- /dev/null +++ b/db/zm_update-1.33.16.sql @@ -0,0 +1,12 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'Notes' + ) > 0, + "SELECT 'Column Notes already exists in Monitors'", + "ALTER TABLE `Monitors` ADD `Notes` TEXT NOT NULL default '' AFTER `Name`" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 2773a4ad0..ffaa075a3 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -23,7 +23,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.33.15 +Version: 1.33.16 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 63984dc0b..c0bd57583 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.33.15 +1.33.16 diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 1353f375b..cc51926fd 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -9,111 +9,112 @@ require_once('Storage.php'); class Monitor extends ZM_Object { protected static $table = 'Monitors'; -protected $defaults = array( - 'Id' => null, - 'Name' => '', - 'ServerId' => 0, - 'StorageId' => 0, - 'Type' => 'Ffmpeg', - 'Function' => 'Mocord', - 'Enabled' => array('type'=>'boolean','default'=>1), - 'LinkedMonitors' => array('type'=>'set', 'default'=>null), - 'Triggers' => array('type'=>'set','default'=>''), - 'Device' => '', - 'Channel' => 0, - 'Format' => '0', - 'V4LMultiBuffer' => null, - 'V4LCapturesPerFrame' => 1, - 'Protocol' => null, - 'Method' => '', - 'Host' => null, - 'Port' => '', - 'SubPath' => '', - 'Path' => null, - 'Options' => null, - 'User' => null, - 'Pass' => null, - // These are NOT NULL default 0 in the db, but 0 is not a valid value. FIXME - 'Width' => null, - 'Height' => null, - 'Colours' => 4, - 'Palette' => '0', - 'Orientation' => null, - 'Deinterlacing' => 0, - 'DecoderHWAccelName' => null, - 'DecoderHWAccelDevice' => null, - 'SaveJPEGs' => 3, - 'VideoWriter' => '0', - 'OutputCodec' => null, - 'OutputContainer' => null, - 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", - 'RecordAudio' => array('type'=>'boolean', 'default'=>0), - 'RTSPDescribe' => array('type'=>'boolean','default'=>0), - 'Brightness' => -1, - 'Contrast' => -1, - 'Hue' => -1, - 'Colour' => -1, - 'EventPrefix' => 'Event-', - 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', - 'LabelX' => 0, - 'LabelY' => 0, - 'LabelSize' => 1, - 'ImageBufferCount' => 100, - 'WarmupCount' => 0, - 'PreEventCount' => 0, - 'PostEventCount' => 0, - 'StreamReplayBuffer' => 0, - 'AlarmFrameCount' => 1, - 'SectionLength' => 600, - 'MinSectionLength' => 10, - 'FrameSkip' => 0, - 'MotionFrameSkip' => 0, - 'AnalysisFPSLimit' => null, - 'AnalysisUpdateDelay' => 0, - 'MaxFPS' => null, - 'AlarmMaxFPS' => null, - 'FPSReportInterval' => 100, - 'RefBlendPerc' => 6, - 'AlarmRefBlendPerc' => 6, - 'Controllable' => array('type'=>'boolean','default'=>0), - 'ControlId' => null, - 'ControlDevice' => null, - 'ControlAddress' => null, - 'AutoStopTimeout' => null, - 'TrackMotion' => array('type'=>'boolean','default'=>0), - 'TrackDelay' => null, - 'ReturnLocation' => -1, - 'ReturnDelay' => null, - 'DefaultRate' => 100, - 'DefaultScale' => 100, - 'SignalCheckPoints' => 0, - 'SignalCheckColour' => '#0000BE', - 'WebColour' => 'red', - 'Exif' => array('type'=>'boolean','default'=>0), - 'Sequence' => null, - 'TotalEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'TotalEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'HourEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'HourEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'DayEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'DayEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'WeekEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'WeekEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'MonthEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'MonthEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'ArchivedEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'ArchivedEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'ZoneCount' => 0, - 'Refresh' => null, - 'DefaultCodec' => 'auto', - 'GroupIds' => array('default'=>array(), 'do_not_update'=>1), -); -private $status_fields = array( - 'Status' => null, - 'AnalysisFPS' => null, - 'CaptureFPS' => null, - 'CaptureBandwidth' => null, -); + protected $defaults = array( + 'Id' => null, + 'Name' => '', + 'Notes' => '', + 'ServerId' => 0, + 'StorageId' => 0, + 'Type' => 'Ffmpeg', + 'Function' => 'Mocord', + 'Enabled' => array('type'=>'boolean','default'=>1), + 'LinkedMonitors' => array('type'=>'set', 'default'=>null), + 'Triggers' => array('type'=>'set','default'=>''), + 'Device' => '', + 'Channel' => 0, + 'Format' => '0', + 'V4LMultiBuffer' => null, + 'V4LCapturesPerFrame' => 1, + 'Protocol' => null, + 'Method' => '', + 'Host' => null, + 'Port' => '', + 'SubPath' => '', + 'Path' => null, + 'Options' => null, + 'User' => null, + 'Pass' => null, + // These are NOT NULL default 0 in the db, but 0 is not a valid value. FIXME + 'Width' => null, + 'Height' => null, + 'Colours' => 4, + 'Palette' => '0', + 'Orientation' => null, + 'Deinterlacing' => 0, + 'DecoderHWAccelName' => null, + 'DecoderHWAccelDevice' => null, + 'SaveJPEGs' => 3, + 'VideoWriter' => '0', + 'OutputCodec' => null, + 'OutputContainer' => null, + 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", + 'RecordAudio' => array('type'=>'boolean', 'default'=>0), + 'RTSPDescribe' => array('type'=>'boolean','default'=>0), + 'Brightness' => -1, + 'Contrast' => -1, + 'Hue' => -1, + 'Colour' => -1, + 'EventPrefix' => 'Event-', + 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', + 'LabelX' => 0, + 'LabelY' => 0, + 'LabelSize' => 1, + 'ImageBufferCount' => 100, + 'WarmupCount' => 0, + 'PreEventCount' => 0, + 'PostEventCount' => 0, + 'StreamReplayBuffer' => 0, + 'AlarmFrameCount' => 1, + 'SectionLength' => 600, + 'MinSectionLength' => 10, + 'FrameSkip' => 0, + 'MotionFrameSkip' => 0, + 'AnalysisFPSLimit' => null, + 'AnalysisUpdateDelay' => 0, + 'MaxFPS' => null, + 'AlarmMaxFPS' => null, + 'FPSReportInterval' => 100, + 'RefBlendPerc' => 6, + 'AlarmRefBlendPerc' => 6, + 'Controllable' => array('type'=>'boolean','default'=>0), + 'ControlId' => null, + 'ControlDevice' => null, + 'ControlAddress' => null, + 'AutoStopTimeout' => null, + 'TrackMotion' => array('type'=>'boolean','default'=>0), + 'TrackDelay' => null, + 'ReturnLocation' => -1, + 'ReturnDelay' => null, + 'DefaultRate' => 100, + 'DefaultScale' => 100, + 'SignalCheckPoints' => 0, + 'SignalCheckColour' => '#0000BE', + 'WebColour' => 'red', + 'Exif' => array('type'=>'boolean','default'=>0), + 'Sequence' => null, + 'TotalEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'TotalEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'HourEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'HourEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'DayEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'DayEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'WeekEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'WeekEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'MonthEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'MonthEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'ArchivedEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'ArchivedEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'ZoneCount' => 0, + 'Refresh' => null, + 'DefaultCodec' => 'auto', + 'GroupIds' => array('default'=>array(), 'do_not_update'=>1), + ); + private $status_fields = array( + 'Status' => null, + 'AnalysisFPS' => null, + 'CaptureFPS' => null, + 'CaptureBandwidth' => null, + ); public function Control() { if ( !property_exists($this, 'Control') ) { diff --git a/web/skins/classic/css/base/views/monitor.css b/web/skins/classic/css/base/views/monitor.css index 2b41e7d06..217b2f374 100644 --- a/web/skins/classic/css/base/views/monitor.css +++ b/web/skins/classic/css/base/views/monitor.css @@ -9,6 +9,10 @@ width: 100%; } +textarea, +input[name="newMonitor[Name]"] { + width: 100%; +} input[name="newMonitor[Width]"], input[name="newMonitor[Height]"] { width: 80px; diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 03e4ce1f8..df3718735 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -40,8 +40,8 @@ if ( !empty($_REQUEST['mid']) ) { if ( $monitor and ZM_OPT_X10 ) $x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['mid'])); } -if ( !$monitor ) { +if ( !$monitor ) { $nextId = getTableAutoInc('Monitors'); if ( isset($_REQUEST['dupId']) ) { $monitor = new ZM\Monitor($_REQUEST['dupId']); @@ -67,7 +67,6 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) { function fourcc($a, $b, $c, $d) { return ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24); } - if ( isset($_REQUEST['newMonitor']) ) { # Update the monitor object with whatever has been set so far. $monitor->set($_REQUEST['newMonitor']); @@ -371,13 +370,6 @@ $label_size = array( 'Large' => 2 ); -$savejpegopts = array( - 'Disabled' => 0, - 'Frames only' => 1, - 'Analysis images only (if available)' => 2, - 'Frames + Analysis images (if available)' => 3, - ); - $codecs = array( 'auto' => translate('Auto'), 'MP4' => translate('MP4'), @@ -459,8 +451,8 @@ foreach ( $tabs as $name=>$value ) { if ( $tab != 'general' ) { ?> + - GroupIds() as $group_id ) { @@ -529,6 +521,7 @@ if ( $tab != 'source' ) { } if ( $tab != 'storage' ) { ?> + @@ -612,6 +605,10 @@ switch ( $tab ) { + + + + Id()] = $Server->Name(); } echo htmlSelect( 'newMonitor[ServerId]', $servers, $monitor->ServerId() ); -?> - - - - - -'Default'); - foreach ( ZM\Storage::find(NULL, array('order'=>'lower(Name)')) as $Storage ) { - $storage_areas[$Storage->Id()] = $Storage->Name(); - } - echo htmlSelect('newMonitor[StorageId]', $storage_areas, $monitor->StorageId()); ?> @@ -921,7 +906,32 @@ if ( $monitor->Type() == 'Local' ) { } case 'storage' : ?> - + + + +'Default'); + foreach ( ZM\Storage::find(NULL, array('order'=>'lower(Name)')) as $Storage ) { + $storage_areas[$Storage->Id()] = $Storage->Name(); + } + echo htmlSelect('newMonitor[StorageId]', $storage_areas, $monitor->StorageId()); +?> + + + + + + 'Disabled', + 1 => 'Frames only', + 2 => 'Analysis images only (if available)', + 3 => 'Frames + Analysis images (if available)', + ); + echo htmlSelect('newMonitor[SaveJPEGs]', $savejpegopts, $monitor->SaveJPEGs()); +?> + + Date: Wed, 18 Dec 2019 19:03:37 -0500 Subject: [PATCH 24/82] Do not set defaults in Object->set(). This allows us to set an empty timestamp. --- web/includes/Object.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index 6a82ec37f..1c17ce312 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -158,14 +158,24 @@ class ZM_Object { # perhaps should turn into a comma-separated string $this->{$k} = implode(',', $v); } else if ( is_string($v) ) { - if ( $v == '' and array_key_exists($k, $this->defaults) ) { - if ( is_array($this->defaults[$k]) ) +if ( 0 ) { +# Remarking this out. We are setting a value, not asking for a default to be set. +# So don't do defaults here, do them somewhere else + if ( ($v == null) and array_key_exists($k, $this->defaults) ) { +Logger::Debug("$k => Have default for $v: "); + if ( is_array($this->defaults[$k]) ) { $this->{$k} = $this->defaults[$k]['default']; - else - $this->{$k} = $this->defaults[$k]; - } else { - $this->{$k} = trim($v); + } else { + $this->{$k} = $this->defaults[$k]; + Logger::Debug("$k => Have default for $v: " . $this->{$k}); + } + } else { + $this->{$k} = trim($v); } +} else { + $this->{$k} = trim($v); +} + } else if ( is_integer($v) ) { $this->{$k} = $v; } else if ( is_bool($v) ) { From 67cc9faa8c7b7fb1e00bb8ede19430565c98caa8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Dec 2019 19:05:06 -0500 Subject: [PATCH 25/82] remove contentForm id from form in state view which isn't used and conflicts if it is used anywhere else. --- web/skins/classic/views/state.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/state.php b/web/skins/classic/views/state.php index 12180000d..16c7708ed 100644 --- a/web/skins/classic/views/state.php +++ b/web/skins/classic/views/state.php @@ -24,7 +24,7 @@ if ( !canEdit('System') ) { } ?>