From 78912584e189ea7d32caa40af8870076b09b34a2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Dec 2019 07:10:33 -0500 Subject: [PATCH 001/111] re-arrange code to hopefully get rid of syntax error reported by some people --- web/includes/functions.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 1710b0ab4..bb36718a7 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2580,21 +2580,23 @@ function html_radio($name, $values, $selected=null, $options=array(), $attrs=arr if ( isset($options['container']) ) { $html .= $options['container'][0]; } + $attributes = array_map( + function($attr, $value){return $attr.'="'.$value.'"';}, + array_keys($attrs), + array_values($attrs) + ); + $attributes_string = implode(' ', $attributes); + $html .= sprintf('
', $name, $value, $label, ($value==$selected?' checked="checked"':''), - implode(' ', array_map( - function($attr, $value){return $attr.'="'.$value.'"';}, - array_keys($attrs), - array_values($attrs) - ), - ), - ( isset($options['id']) ? $options['id'] : ''), + $attributes_string, + (isset($options['id']) ? $options['id'] : ''), ( ( (!isset($options['inline'])) or $options['inline'] ) ? '-inline' : ''), - ); + ); if ( isset($options['container']) ) { $html .= $options['container'][1]; } From df9f6103e4589f68c18a46d05c6723d059d2fee4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Dec 2019 09:00:20 -0500 Subject: [PATCH 002/111] fix syntax error --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index bb36718a7..aea0c8b14 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2595,7 +2595,7 @@ function html_radio($name, $values, $selected=null, $options=array(), $attrs=arr ', $name, $value, $label, ($value==$selected?' checked="checked"':''), $attributes_string, (isset($options['id']) ? $options['id'] : ''), - ( ( (!isset($options['inline'])) or $options['inline'] ) ? '-inline' : ''), + ( ( (!isset($options['inline'])) or $options['inline'] ) ? '-inline' : '') ); if ( isset($options['container']) ) { $html .= $options['container'][1]; From eee3729b854cb6e40d9f5fb1698c1e2ea60e35aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Dec 2019 22:23:55 -0500 Subject: [PATCH 003/111] 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 004/111] 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 e123e689cac837455d97149bde08cf06ab148d61 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Dec 2019 14:31:06 -0500 Subject: [PATCH 005/111] 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 3f8092a430a4acac70456ed4a71a399d1aef9873 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Dec 2019 17:25:41 -0500 Subject: [PATCH 006/111] Add funding.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..8804e639c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [connortechnology,pliablepixels] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: zoneminder # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From bda4e95c7abd6f6ce1f7cad3b46d359c5713ecc0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Dec 2019 17:51:06 -0500 Subject: [PATCH 007/111] Add irc to badges --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9be80d4b7..b9d215a40 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ ZoneMinder ========== -[![Build Status](https://travis-ci.org/ZoneMinder/zoneminder.png)](https://travis-ci.org/ZoneMinder/zoneminder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) - +[![Build Status](https://travis-ci.org/ZoneMinder/zoneminder.png)](https://travis-ci.org/ZoneMinder/zoneminder) +[![Bounty Source](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) [![Join Slack](https://github.com/ozonesecurity/ozonebase/blob/master/img/slacksm.png?raw=true)](https://join.slack.com/t/zoneminder-chat/shared_invite/enQtNTU0NDkxMDM5NDQwLTdhZmQ5Y2M2NWQyN2JkYTBiN2ZkMzIzZGQ0MDliMTRmM2FjZWRlYzUwYTQ2MjMwMTVjMzQ1NjYxOTdmMjE2MTE) +[![IRC Network](https://img.shields.io/badge/irc-%23zoneminder-blue.svg "IRC Freenode")](https://webchat.freenode.net/?channels=zoneminder) All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org From cc6d40d67ef6a4bc09e2da44be9ea3b189e451e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 7 Dec 2019 10:38:51 -0500 Subject: [PATCH 008/111] Missing -> --- web/includes/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Server.php b/web/includes/Server.php index 93a59bfed..c0fd27a38 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -80,7 +80,7 @@ class Server extends ZM_Object { public function PathToZMS( $new = null ) { if ( $new != null ) - $this{'PathToZMS'} = $new; + $this->{'PathToZMS'} = $new; if ( $this->Id() and $this->{'PathToZMS'} ) { return $this->{'PathToZMS'}; } else { From 4632bbd12424068ece63a3652470bc09a00ea593 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 7 Dec 2019 11:45:32 -0500 Subject: [PATCH 009/111] 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 010/111] 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 011/111] 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 012/111] 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 013/111] 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 014/111] 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 015/111] 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 016/111] 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 017/111] 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 018/111] 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 019/111] 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 020/111] 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 021/111] 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 022/111] 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 023/111] 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 024/111] 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 025/111] 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 026/111] 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 027/111] 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 028/111] 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 029/111] 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 030/111] 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 031/111] 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') ) { } ?>