2015-09-18 03:29:36 +08:00
< ? php
2019-02-22 22:19:07 +08:00
namespace ZM ;
2018-05-16 01:45:47 +08:00
require_once ( 'database.php' );
2019-09-09 00:26:11 +08:00
require_once ( 'Object.php' );
2019-09-20 02:55:27 +08:00
require_once ( 'Control.php' );
2020-09-01 06:30:05 +08:00
require_once ( 'Group.php' );
2021-07-07 21:46:36 +08:00
require_once ( 'Manufacturer.php' );
require_once ( 'Model.php' );
require_once ( 'Server.php' );
require_once ( 'Storage.php' );
2020-09-01 06:30:05 +08:00
$FunctionTypes = null ;
function getMonitorFunctionTypes () {
2021-05-29 00:29:30 +08:00
if ( ! isset ( $FunctionTypes )) {
2020-09-01 06:30:05 +08:00
$FunctionTypes = array (
'None' => translate ( 'FnNone' ),
'Monitor' => translate ( 'FnMonitor' ),
'Modect' => translate ( 'FnModect' ),
2020-09-04 06:20:51 +08:00
'Record' => translate ( 'FnRecord' ),
2020-09-03 22:40:10 +08:00
'Mocord' => translate ( 'FnMocord' ),
2020-09-01 06:30:05 +08:00
'Nodect' => translate ( 'FnNodect' )
);
}
return $FunctionTypes ;
}
2015-09-18 03:29:36 +08:00
2021-05-29 00:29:30 +08:00
$Statuses = null ;
function getMonitorStatuses () {
if ( ! isset ( $Statuses )) {
$Statuses = array (
- 1 => 'Unknown' ,
0 => 'Idle' ,
1 => 'PreAlarm' ,
2 => 'Alarm' ,
3 => 'Alert' ,
4 => 'Tape'
);
}
return $Statuses ;
}
2019-09-09 00:26:11 +08:00
class Monitor extends ZM_Object {
protected static $table = 'Monitors' ;
2018-09-15 21:52:08 +08:00
2019-12-19 01:13:00 +08:00
protected $defaults = array (
'Id' => null ,
2021-02-02 05:43:24 +08:00
'Name' => array ( 'type' => 'text' , 'filter_regexp' => '/[^\w\-\.\(\)\:\/ ]/' , 'default' => 'Monitor' ),
2019-12-19 01:13:00 +08:00
'Notes' => '' ,
'ServerId' => 0 ,
'StorageId' => 0 ,
2021-09-25 22:32:04 +08:00
'ManufacturerId' => null ,
'ModelId' => null ,
2019-12-19 01:13:00 +08:00
'Type' => 'Ffmpeg' ,
'Function' => 'Mocord' ,
'Enabled' => array ( 'type' => 'boolean' , 'default' => 1 ),
2020-12-11 03:06:26 +08:00
'DecodingEnabled' => array ( 'type' => 'boolean' , 'default' => 1 ),
2019-12-19 01:13:00 +08:00
'LinkedMonitors' => array ( 'type' => 'set' , 'default' => null ),
'Triggers' => array ( 'type' => 'set' , 'default' => '' ),
2021-11-27 08:22:07 +08:00
'EventStartCommand' => '' ,
'EventEndCommand' => '' ,
2020-05-13 03:47:00 +08:00
'ONVIF_URL' => '' ,
'ONVIF_Username' => '' ,
'ONVIF_Password' => '' ,
'ONVIF_Options' => '' ,
2019-12-19 01:13:00 +08:00
'Device' => '' ,
'Channel' => 0 ,
'Format' => '0' ,
'V4LMultiBuffer' => null ,
'V4LCapturesPerFrame' => 1 ,
'Protocol' => null ,
'Method' => '' ,
'Host' => null ,
'Port' => '' ,
'SubPath' => '' ,
'Path' => null ,
2021-03-03 22:55:23 +08:00
'SecondPath' => null ,
2019-12-19 01:13:00 +08:00
'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' ,
2020-05-02 03:32:26 +08:00
'Orientation' => 'ROTATE_0' ,
2019-12-19 01:13:00 +08:00
'Deinterlacing' => 0 ,
'DecoderHWAccelName' => null ,
'DecoderHWAccelDevice' => null ,
'SaveJPEGs' => 3 ,
'VideoWriter' => '0' ,
'OutputCodec' => null ,
2020-05-03 06:03:42 +08:00
'Encoder' => 'auto' ,
2019-12-19 01:13:00 +08:00
'OutputContainer' => null ,
2021-04-01 22:14:02 +08:00
'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 " ,
2019-12-19 01:13:00 +08:00
'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 ,
2021-03-23 00:05:36 +08:00
'ImageBufferCount' => 3 ,
2021-03-27 05:02:17 +08:00
'MaxImageBufferCount' => 0 ,
2019-12-19 01:13:00 +08:00
'WarmupCount' => 0 ,
2019-12-28 23:49:42 +08:00
'PreEventCount' => 5 ,
'PostEventCount' => 5 ,
2019-12-19 01:13:00 +08:00
'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 ,
2021-04-24 00:56:45 +08:00
'ModectDuringPTZ' => array ( 'type' => 'boolean' , 'default' => 0 ),
2019-12-19 01:13:00 +08:00
'DefaultRate' => 100 ,
2020-12-17 22:45:06 +08:00
'DefaultScale' => 0 ,
2019-12-19 01:13:00 +08:00
'SignalCheckPoints' => 0 ,
'SignalCheckColour' => '#0000BE' ,
2020-01-01 08:10:29 +08:00
'WebColour' => '#ff0000' ,
2021-02-03 03:24:23 +08:00
'Exif' => array ( 'type' => 'boolean' , 'default' => 0 ),
2019-12-19 01:13:00 +08:00
'Sequence' => null ,
'ZoneCount' => 0 ,
'Refresh' => null ,
'DefaultCodec' => 'auto' ,
'GroupIds' => array ( 'default' => array (), 'do_not_update' => 1 ),
2020-09-24 21:01:30 +08:00
'Latitude' => null ,
'Longitude' => null ,
2021-02-03 03:24:23 +08:00
'RTSPServer' => array ( 'type' => 'boolean' , 'default' => 0 ),
2021-02-28 01:28:59 +08:00
'RTSPStreamName' => '' ,
2021-09-09 00:52:33 +08:00
'Importance' => 'Normal' ,
2019-12-19 01:13:00 +08:00
);
private $status_fields = array (
'Status' => null ,
'AnalysisFPS' => null ,
'CaptureFPS' => null ,
'CaptureBandwidth' => null ,
2021-04-10 07:46:25 +08:00
);
private $summary_fields = array (
2020-11-07 03:00:18 +08:00
'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 ),
2019-12-19 01:13:00 +08:00
);
2015-12-02 03:03:55 +08:00
2019-09-20 02:55:27 +08:00
public function Control () {
2021-08-18 22:50:45 +08:00
if ( ! property_exists ( $this , 'Control' )) {
if ( $this -> ControlId ())
2019-09-20 02:55:27 +08:00
$this -> { 'Control' } = Control :: find_one ( array ( 'Id' => $this -> { 'ControlId' }));
2016-05-06 03:30:24 +08:00
2021-08-18 22:50:45 +08:00
if ( ! ( property_exists ( $this , 'Control' ) and $this -> { 'Control' }))
2019-09-20 02:55:27 +08:00
$this -> { 'Control' } = new Control ();
}
return $this -> { 'Control' };
}
2018-04-18 01:51:20 +08:00
2016-05-06 03:30:24 +08:00
public function Server () {
2021-08-18 22:50:45 +08:00
if ( ! property_exists ( $this , 'Server' )) {
if ( $this -> ServerId ())
2020-01-11 09:15:52 +08:00
$this -> { 'Server' } = Server :: find_one ( array ( 'Id' => $this -> { 'ServerId' }));
2021-08-18 22:50:45 +08:00
if ( ! property_exists ( $this , 'Server' )) {
2020-01-11 09:13:09 +08:00
$this -> { 'Server' } = new Server ();
}
}
return $this -> { 'Server' };
2016-05-06 03:30:24 +08:00
}
2019-09-20 02:55:27 +08:00
2021-08-18 22:50:45 +08:00
public function __call ( $fn , array $args ) {
if ( count ( $args )) {
if ( is_array ( $this -> defaults [ $fn ]) and $this -> defaults [ $fn ][ 'type' ] == 'set' ) {
2021-02-02 05:43:24 +08:00
$this -> { $fn } = is_array ( $args [ 0 ]) ? implode ( ',' , $args [ 0 ]) : $args [ 0 ];
2019-09-20 02:55:27 +08:00
} else {
$this -> { $fn } = $args [ 0 ];
}
2017-06-06 03:21:27 +08:00
}
2021-08-18 22:50:45 +08:00
if ( property_exists ( $this , $fn )) {
2016-05-06 03:30:24 +08:00
return $this -> { $fn };
2021-08-18 22:50:45 +08:00
} else if ( array_key_exists ( $fn , $this -> defaults )) {
2019-09-20 02:55:27 +08:00
if ( is_array ( $this -> defaults [ $fn ]) ) {
return $this -> defaults [ $fn ][ 'default' ];
}
return $this -> defaults [ $fn ];
2021-08-18 22:50:45 +08:00
} else if ( array_key_exists ( $fn , $this -> status_fields )) {
2021-04-10 07:46:25 +08:00
$sql = 'SELECT * FROM `Monitor_Status` WHERE `MonitorId`=?' ;
2019-07-08 05:25:49 +08:00
$row = dbFetchOne ( $sql , NULL , array ( $this -> { 'Id' }));
2021-08-18 22:50:45 +08:00
if ( ! $row ) {
2020-10-14 23:32:33 +08:00
Warning ( 'Unable to load Monitor status record for Id=' . $this -> { 'Id' } . ' using ' . $sql );
2021-04-10 07:46:25 +08:00
return null ;
} else {
foreach ( $row as $k => $v ) {
2019-09-25 22:13:56 +08:00
$this -> { $k } = $v ;
}
2021-04-10 07:46:25 +08:00
}
return $this -> { $fn };
2021-08-18 22:50:45 +08:00
} else if ( array_key_exists ( $fn , $this -> summary_fields )) {
2021-04-10 07:46:25 +08:00
$sql = 'SELECT * FROM `Event_Summaries` WHERE `MonitorId`=?' ;
$row = dbFetchOne ( $sql , NULL , array ( $this -> { 'Id' }));
2021-08-18 22:50:45 +08:00
if ( ! $row ) {
2021-04-10 07:46:25 +08:00
Warning ( 'Unable to load Event Summary record for Id=' . $this -> { 'Id' } . ' using ' . $sql );
return null ;
2016-06-21 00:41:14 +08:00
} else {
2019-07-08 05:25:49 +08:00
foreach ( $row as $k => $v ) {
$this -> { $k } = $v ;
}
2016-06-21 00:41:14 +08:00
}
2019-07-08 05:25:49 +08:00
return $this -> { $fn };
} else {
$backTrace = debug_backtrace ();
$file = $backTrace [ 1 ][ 'file' ];
$line = $backTrace [ 1 ][ 'line' ];
2019-09-20 02:55:27 +08:00
Warning ( " Unknown function call Monitor-> $fn from $file : $line " );
2016-06-15 00:38:17 +08:00
}
2016-05-06 03:30:24 +08:00
}
2017-02-28 10:48:08 +08:00
2018-07-10 00:09:29 +08:00
public function getStreamSrc ( $args , $querySep = '&' ) {
2018-11-30 03:26:30 +08:00
$streamSrc = $this -> Server () -> UrlToZMS (
2018-07-10 00:09:29 +08:00
ZM_MIN_STREAMING_PORT ?
ZM_MIN_STREAMING_PORT + $this -> { 'Id' } :
null );
2015-09-18 03:29:36 +08:00
2017-02-28 10:48:08 +08:00
$args [ 'monitor' ] = $this -> { 'Id' };
2015-09-18 03:29:36 +08:00
2021-08-18 22:50:45 +08:00
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
2018-06-26 02:50:54 +08:00
$args [ 'auth' ] = generateAuthHash ( ZM_AUTH_HASH_IPS );
2017-02-28 10:48:08 +08:00
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$args [ 'user' ] = $_SESSION [ 'username' ];
$args [ 'pass' ] = $_SESSION [ 'password' ];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$args [ 'user' ] = $_SESSION [ 'username' ];
2016-05-06 03:30:24 +08:00
}
}
2021-08-18 22:50:45 +08:00
if (( ! isset ( $args [ 'mode' ])) or ( $args [ 'mode' ] != 'single' )) {
2020-09-03 01:56:55 +08:00
$args [ 'connkey' ] = $this -> connKey ();
2016-05-06 03:30:24 +08:00
}
2021-08-18 22:50:45 +08:00
if ( ZM_RAND_STREAM ) {
2017-02-28 10:48:08 +08:00
$args [ 'rand' ] = time ();
2016-05-06 03:30:24 +08:00
}
2020-08-25 02:35:59 +08:00
# zms doesn't support width & height, so if no scale is set, default it
2021-08-18 22:50:45 +08:00
if ( ! isset ( $args [ 'scale' ])) {
if ( isset ( $args [ 'width' ]) and intval ( $args [ 'width' ])) {
2020-08-25 02:35:59 +08:00
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'width' ])) / $this -> ViewWidth ());
2021-08-18 22:50:45 +08:00
} else if ( isset ( $args [ 'height' ]) and intval ( $args [ 'height' ])) {
2020-08-25 02:35:59 +08:00
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'height' ])) / $this -> ViewHeight ());
2020-07-14 02:50:21 +08:00
}
}
2021-08-18 22:50:45 +08:00
if ( isset ( $args [ 'width' ]))
2020-08-27 22:29:50 +08:00
unset ( $args [ 'width' ]);
2021-08-18 22:50:45 +08:00
if ( isset ( $args [ 'height' ]))
2020-08-27 22:29:50 +08:00
unset ( $args [ 'height' ]);
2015-09-18 03:29:36 +08:00
2019-03-22 02:14:15 +08:00
$streamSrc .= '?' . http_build_query ( $args , '' , $querySep );
2015-09-18 03:29:36 +08:00
2018-07-10 00:09:29 +08:00
return $streamSrc ;
2016-05-06 03:30:24 +08:00
} // end function getStreamSrc
2016-06-15 00:38:17 +08:00
2019-10-30 05:39:12 +08:00
public function isPortrait () {
return $this -> ViewWidth () > $this -> ViewHeight ();
}
public function isLandscape () {
return $this -> ViewWidth () < $this -> ViewHeight ();
}
public function ViewWidth ( $new = null ) {
2021-08-18 22:50:45 +08:00
if ( $new )
2017-10-27 09:56:10 +08:00
$this -> { 'Width' } = $new ;
2019-11-30 02:56:02 +08:00
$field = ( $this -> Orientation () == 'ROTATE_90' or $this -> Orientation () == 'ROTATE_270' ) ? 'Height' : 'Width' ;
2021-08-18 22:50:45 +08:00
if ( property_exists ( $this , $field ))
2018-05-06 00:49:00 +08:00
return $this -> { $field };
2019-12-08 00:45:32 +08:00
return $this -> defaults [ $field ];
2018-05-06 00:49:00 +08:00
} // end function Width
2016-06-15 00:38:17 +08:00
2019-10-30 05:39:12 +08:00
public function ViewHeight ( $new = null ) {
2021-08-18 22:50:45 +08:00
if ( $new )
2017-10-27 09:56:10 +08:00
$this -> { 'Height' } = $new ;
2018-05-06 00:49:00 +08:00
2019-11-30 02:56:02 +08:00
$field = ( $this -> Orientation () == 'ROTATE_90' or $this -> Orientation () == 'ROTATE_270' ) ? 'Width' : 'Height' ;
2021-08-18 22:50:45 +08:00
if ( property_exists ( $this , $field ))
2018-05-06 00:49:00 +08:00
return $this -> { $field };
2019-12-08 00:45:32 +08:00
return $this -> defaults [ $field ];
2018-05-06 00:49:00 +08:00
} // end function Height
2016-06-15 00:38:17 +08:00
2019-02-10 08:41:54 +08:00
public function SignalCheckColour ( $new = null ) {
$field = 'SignalCheckColour' ;
if ( $new ) {
$this -> { $field } = $new ;
}
// Validate that it's a valid colour (we seem to allow color names, not just hex).
// This also helps prevent XSS.
2021-08-18 22:50:45 +08:00
if ( property_exists ( $this , $field ) && preg_match ( '/^[#0-9a-zA-Z]+$/' , $this -> { $field })) {
2019-02-10 08:41:54 +08:00
return $this -> { $field };
}
2019-12-08 00:45:32 +08:00
return $this -> defaults [ $field ];
2019-02-10 08:41:54 +08:00
} // end function SignalCheckColour
2021-08-18 22:50:45 +08:00
public static function find ( $parameters = array (), $options = array ()) {
2019-09-09 00:26:11 +08:00
return ZM_Object :: _find ( get_class (), $parameters , $options );
2016-05-06 03:30:24 +08:00
}
2017-12-22 23:12:34 +08:00
2021-08-18 22:50:45 +08:00
public static function find_one ( $parameters = array (), $options = array ()) {
2019-09-09 00:26:11 +08:00
return ZM_Object :: _find_one ( get_class (), $parameters , $options );
}
2017-11-06 00:54:00 +08:00
2021-08-18 22:50:45 +08:00
function zmcControl ( $mode = false ) {
if ( ! ( property_exists ( $this , 'Id' ) and $this -> { 'Id' })) {
2019-09-24 00:39:24 +08:00
Warning ( 'Attempt to control a monitor with no Id' );
2019-09-20 02:55:27 +08:00
return ;
}
2021-08-18 22:50:45 +08:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) )) {
if ( $this -> Type () == 'Local' ) {
2017-10-24 08:00:59 +08:00
$zmcArgs = '-d ' . $this -> { 'Device' };
} else {
$zmcArgs = '-m ' . $this -> { 'Id' };
}
2021-08-18 22:50:45 +08:00
if ( $mode == 'stop' ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2017-10-24 08:00:59 +08:00
} else {
2021-08-18 22:50:45 +08:00
if ( $mode == 'restart' ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2017-10-24 08:00:59 +08:00
}
2021-08-18 22:50:45 +08:00
if ( $this -> { 'Function' } != 'None' ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'start' , 'zmc' , $zmcArgs );
2018-01-19 04:38:48 +08:00
}
2017-10-24 08:00:59 +08:00
}
2021-08-18 22:50:45 +08:00
} else if ( $this -> ServerId ()) {
2017-10-24 08:00:59 +08:00
$Server = $this -> Server ();
2018-12-11 23:21:22 +08:00
$url = $Server -> UrlToApi () . '/monitors/daemonControl/' . $this -> { 'Id' } . '/' . $mode . '/zmc.json' ;
2021-08-18 22:50:45 +08:00
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
2020-02-26 06:00:16 +08:00
$url .= '?auth=' . generateAuthHash ( ZM_AUTH_HASH_IPS );
2021-08-18 22:50:45 +08:00
} else if ( ZM_AUTH_RELAY == 'plain' ) {
2020-02-26 06:00:16 +08:00
$url .= '?user=' . $_SESSION [ 'username' ];
$url .= '?pass=' . $_SESSION [ 'password' ];
2020-02-26 06:12:48 +08:00
} else {
Error ( 'Multi-Server requires AUTH_RELAY be either HASH or PLAIN' );
return ;
2017-10-24 08:00:59 +08:00
}
}
2020-10-14 22:39:25 +08:00
Debug ( 'sending command to ' . $url );
2018-11-15 02:00:19 +08:00
2021-08-18 22:50:45 +08:00
$context = stream_context_create ();
2018-01-19 04:38:48 +08:00
try {
$result = file_get_contents ( $url , false , $context );
2021-08-18 22:50:45 +08:00
if ( $result === FALSE ) { /* Handle error */
2018-01-19 04:38:48 +08:00
Error ( " Error restarting zmc using $url " );
}
2021-08-18 22:50:45 +08:00
} catch ( Exception $e ) {
2018-01-19 04:38:48 +08:00
Error ( " Except $e thrown trying to restart zmc " );
}
2018-06-12 04:34:23 +08:00
} else {
2019-09-24 00:39:24 +08:00
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
2017-10-24 08:00:59 +08:00
}
} // end function zmcControl
2018-01-19 04:38:48 +08:00
2021-08-18 22:50:45 +08:00
public function GroupIds ( $new = '' ) {
if ( $new != '' ) {
if ( ! is_array ( $new )) {
2018-04-25 21:27:43 +08:00
$this -> { 'GroupIds' } = array ( $new );
} else {
$this -> { 'GroupIds' } = $new ;
}
}
2021-08-18 22:50:45 +08:00
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' })
2018-04-25 21:27:43 +08:00
$this -> { 'GroupIds' } = array ();
2018-02-28 03:19:20 +08:00
} else {
2018-03-24 04:34:46 +08:00
$this -> { 'GroupIds' } = array ();
2018-02-28 03:19:20 +08:00
}
}
return $this -> { 'GroupIds' };
}
2019-09-20 02:55:27 +08:00
2018-03-21 03:18:07 +08:00
public function delete () {
2021-08-18 22:50:45 +08:00
if ( ! $this -> { 'Id' }) {
Warning ( 'Attempt to delete a monitor without id.' );
2019-11-02 22:12:43 +08:00
return ;
}
2018-03-21 03:18:07 +08:00
$this -> zmcControl ( 'stop' );
// If fast deletes are on, then zmaudit will clean everything else up later
// If fast deletes are off and there are lots of events then this step may
// well time out before completing, in which case zmaudit will still tidy up
2021-08-18 22:50:45 +08:00
if ( ! ZM_OPT_FAST_DELETE ) {
2018-03-22 02:32:54 +08:00
$markEids = dbFetchAll ( 'SELECT Id FROM Events WHERE MonitorId=?' , 'Id' , array ( $this -> { 'Id' }));
2019-09-20 02:55:27 +08:00
foreach ( $markEids as $markEid )
2018-03-22 02:32:54 +08:00
deleteEvent ( $markEid );
2018-03-21 03:18:07 +08:00
2021-08-18 22:50:45 +08:00
if ( $this -> { 'Name' })
2019-11-02 22:12:43 +08:00
deletePath ( ZM_DIR_EVENTS . '/' . basename ( $this -> { 'Name' }));
2018-03-21 03:18:07 +08:00
deletePath ( ZM_DIR_EVENTS . '/' . $this -> { 'Id' });
$Storage = $this -> Storage ();
2021-08-18 22:50:45 +08:00
if ( $Storage -> Path () != ZM_DIR_EVENTS ) {
if ( $this -> { 'Name' })
2019-11-02 22:12:43 +08:00
deletePath ( $Storage -> Path () . '/' . basename ( $this -> { 'Name' }));
2018-03-21 03:18:07 +08:00
deletePath ( $Storage -> Path () . '/' . $this -> { 'Id' });
}
2019-09-20 02:55:27 +08:00
} // end if !ZM_OPT_FAST_DELETE
2018-03-21 03:18:07 +08:00
// This is the important stuff
dbQuery ( 'DELETE FROM Zones WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
if ( ZM_OPT_X10 )
dbQuery ( 'DELETE FROM TriggersX10 WHERE MonitorId=?' , array ( $this -> { 'Id' }));
2021-04-10 07:46:25 +08:00
dbQuery ( 'DELETE FROM Monitor_Status WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
dbQuery ( 'DELETE FROM Event_Summaries WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
2018-03-21 03:18:07 +08:00
dbQuery ( 'DELETE FROM Monitors WHERE Id = ?' , array ( $this -> { 'Id' }));
} // end function delete
2018-03-22 02:32:54 +08:00
2019-09-20 02:55:27 +08:00
public function Storage ( $new = null ) {
2021-08-18 22:50:45 +08:00
if ( $new ) {
2018-03-22 02:32:54 +08:00
$this -> { 'Storage' } = $new ;
}
2021-08-18 22:50:45 +08:00
if ( ! ( property_exists ( $this , 'Storage' ) and $this -> { 'Storage' })) {
2020-08-25 02:35:59 +08:00
$this -> { 'Storage' } = isset ( $this -> { 'StorageId' }) ?
Storage :: find_one ( array ( 'Id' => $this -> { 'StorageId' })) :
2018-04-11 04:05:37 +08:00
new Storage ( NULL );
2021-08-18 22:50:45 +08:00
if ( ! $this -> { 'Storage' })
2018-05-24 21:54:45 +08:00
$this -> { 'Storage' } = new Storage ( NULL );
2018-03-22 02:32:54 +08:00
}
return $this -> { 'Storage' };
}
2018-05-04 21:46:46 +08:00
public function Source ( ) {
$source = '' ;
2021-08-18 22:50:45 +08:00
if ( $this -> { 'Type' } == 'Local' ) {
2018-05-04 21:46:46 +08:00
$source = $this -> { 'Device' } . ' (' . $this -> { 'Channel' } . ')' ;
2021-08-18 22:50:45 +08:00
} else if ( $this -> { 'Type' } == 'Remote' ) {
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' });
if ( $this -> { 'Port' } != '80' and $this -> { 'Port' } != '554' ) {
2018-05-04 21:46:46 +08:00
$source .= ':' . $this -> { 'Port' };
}
2021-08-18 22:50:45 +08:00
} else if ( $this -> { 'Type' } == 'VNC' ) {
2020-03-30 22:10:06 +08:00
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' } );
2021-08-18 22:50:45 +08:00
if ( $this -> { 'Port' } != '5900' ) {
2020-03-30 22:10:06 +08:00
$source .= ':' . $this -> { 'Port' };
}
2021-08-18 22:50:45 +08:00
} else if ( $this -> { 'Type' } == 'Ffmpeg' || $this -> { 'Type' } == 'Libvlc' || $this -> { 'Type' } == 'WebSite' ) {
$url_parts = parse_url ( $this -> { 'Path' });
if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) {
2018-11-22 23:04:33 +08:00
# Filter out everything but the hostname
2021-08-18 22:50:45 +08:00
if ( isset ( $url_parts [ 'host' ])) {
2018-09-15 02:26:45 +08:00
$source = $url_parts [ 'host' ];
} else {
$source = $this -> { 'Path' };
}
2021-08-18 22:50:45 +08:00
} else if ( ZM_WEB_FILTER_SOURCE == 'NoCredentials' ) {
2018-07-10 00:09:29 +08:00
# Filter out sensitive and common items
2018-06-20 23:12:43 +08:00
unset ( $url_parts [ 'user' ]);
unset ( $url_parts [ 'pass' ]);
#unset($url_parts['scheme']);
unset ( $url_parts [ 'query' ]);
#unset($url_parts['path']);
2021-08-18 22:50:45 +08:00
if ( isset ( $url_parts [ 'port' ]) and ( $url_parts [ 'port' ] == '80' or $url_parts [ 'port' ] == '554' ))
2018-06-20 23:12:43 +08:00
unset ( $url_parts [ 'port' ]);
$source = unparse_url ( $url_parts );
2020-08-25 02:35:59 +08:00
} else { # Don't filter anything
2018-06-20 23:12:43 +08:00
$source = $this -> { 'Path' };
}
2018-05-04 21:46:46 +08:00
}
2021-08-18 22:50:45 +08:00
if ( $source == '' ) {
2018-05-04 21:46:46 +08:00
$source = 'Monitor ' . $this -> { 'Id' };
}
return $source ;
} // end function Source
2018-09-08 04:31:11 +08:00
2019-12-14 00:50:11 +08:00
public function UrlToIndex ( $port = null ) {
return $this -> Server () -> UrlToIndex ( $port );
2018-09-15 02:26:45 +08:00
}
2018-09-08 04:31:11 +08:00
2021-11-11 03:18:58 +08:00
public function UrlToZMS ( $port = null ) {
return $this -> Server () -> UrlToZMS ( $port ) . '?mid=' . $this -> Id ();
}
2020-01-01 01:42:49 +08:00
public function sendControlCommand ( $command ) {
// command is generally a command option list like --command=blah but might be just the word quit
2019-10-09 06:07:33 +08:00
2020-01-01 01:42:49 +08:00
$options = array ();
# Convert from a command line params to an option array
2021-08-18 22:50:45 +08:00
foreach ( explode ( ' ' , $command ) as $option ) {
if ( preg_match ( '/--([^=]+)(?:=(.+))?/' , $option , $matches )) {
2020-01-01 01:42:49 +08:00
$options [ $matches [ 1 ]] = $matches [ 2 ] ? $matches [ 2 ] : 1 ;
2021-08-18 22:50:45 +08:00
} else if ( $option != '' and $option != 'quit' and $option != 'start' and $option != 'stop' ) {
2020-01-01 01:42:49 +08:00
Warning ( " Ignored command for zmcontrol $option in $command " );
}
2019-10-09 06:07:33 +08:00
}
2021-08-18 22:50:45 +08:00
if ( ! count ( $options )) {
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
2020-04-30 04:30:59 +08:00
# These are special as we now run zmcontrol as a daemon through zmdc.
$status = daemonStatus ( 'zmcontrol.pl' , array ( '--id' , $this -> { 'Id' }));
2020-10-14 22:39:25 +08:00
Debug ( " Current status $status " );
2021-08-18 22:50:45 +08:00
if ( $status or (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' })))) {
2020-04-30 04:30:59 +08:00
daemonControl ( $command , 'zmcontrol.pl' , '--id ' . $this -> { 'Id' });
return ;
}
$options [ 'command' ] = $command ;
2020-01-01 01:42:49 +08:00
} else {
2021-08-18 22:50:45 +08:00
Warning ( 'No commands to send to zmcontrol from ' . $command );
2020-01-01 01:42:49 +08:00
return false ;
}
2019-10-09 06:07:33 +08:00
}
2021-08-18 22:50:45 +08:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }))) {
2020-01-01 01:42:49 +08:00
# Local
2020-10-14 22:39:25 +08:00
Debug ( 'Trying to send options ' . print_r ( $options , true ));
2020-01-01 01:42:49 +08:00
$optionString = jsonEncode ( $options );
2021-08-18 22:50:45 +08:00
Debug ( 'Trying to send options ' . $optionString );
2020-01-01 01:42:49 +08:00
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
$socket = socket_create ( AF_UNIX , SOCK_STREAM , 0 );
2021-08-18 22:50:45 +08:00
if ( $socket < 0 ) {
2020-01-01 01:42:49 +08:00
Error ( 'socket_create() failed: ' . socket_strerror ( $socket ));
return false ;
2019-10-09 06:07:33 +08:00
}
2020-01-01 01:42:49 +08:00
$sockFile = ZM_PATH_SOCKS . '/zmcontrol-' . $this -> { 'Id' } . '.sock' ;
2021-08-18 22:50:45 +08:00
if ( @ socket_connect ( $socket , $sockFile )) {
if ( ! socket_write ( $socket , $optionString )) {
2020-01-01 01:42:49 +08:00
Error ( 'Can\'t write to control socket: ' . socket_strerror ( socket_last_error ( $socket )));
2020-01-06 06:30:06 +08:00
return false ;
2020-01-01 01:42:49 +08:00
}
2021-08-18 22:50:45 +08:00
} else if ( $command != 'quit' ) {
2020-09-21 23:24:17 +08:00
$command = ZM_PATH_BIN . '/zmcontrol.pl ' . $command . ' --id ' . $this -> { 'Id' };
2019-10-09 06:07:33 +08:00
2020-01-01 01:42:49 +08:00
// Can't connect so use script
$ctrlOutput = exec ( escapeshellcmd ( $command ));
}
socket_close ( $socket );
2021-08-18 22:50:45 +08:00
} else if ( $this -> ServerId ()) {
2019-10-09 06:07:33 +08:00
$Server = $this -> Server ();
2020-07-21 04:25:29 +08:00
$url = $Server -> UrlToApi () . '/monitors/daemonControl/' . $this -> { 'Id' } . '/' . $command . '/zmcontrol.pl.json' ;
2021-08-18 22:50:45 +08:00
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
2020-04-30 04:30:59 +08:00
$url .= '?auth=' . generateAuthHash ( ZM_AUTH_HASH_IPS );
2021-08-18 22:50:45 +08:00
} else if ( ZM_AUTH_RELAY == 'plain' ) {
2020-04-30 04:30:59 +08:00
$url .= '?user=' . $_SESSION [ 'username' ];
$url .= '?pass=' . $_SESSION [ 'password' ];
2021-08-18 22:50:45 +08:00
} else if ( ZM_AUTH_RELAY == 'none' ) {
2020-04-30 04:30:59 +08:00
$url .= '?user=' . $_SESSION [ 'username' ];
2019-10-09 06:07:33 +08:00
}
}
2021-08-18 22:50:45 +08:00
Debug ( 'sending command to ' . $url );
2019-10-09 06:07:33 +08:00
$context = stream_context_create ();
try {
$result = file_get_contents ( $url , false , $context );
2021-08-18 22:50:45 +08:00
if ( $result === FALSE ) { /* Handle error */
2020-03-27 01:57:00 +08:00
Error ( " Error sending command using $url " );
2019-10-09 06:07:33 +08:00
return false ;
}
2021-08-18 22:50:45 +08:00
} catch ( Exception $e ) {
2020-03-27 01:57:00 +08:00
Error ( " Exception $e thrown trying to send command to $url " );
2020-01-06 06:30:06 +08:00
return false ;
2019-10-09 06:07:33 +08:00
}
} else {
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
return false ;
} // end if we are on the recording server
return true ;
} // end function sendControlCommand($mid, $command)
2020-09-01 06:30:05 +08:00
function Groups ( $new = '' ) {
2021-08-18 22:50:45 +08:00
if ( $new != '' )
2020-09-01 06:30:05 +08:00
$this -> Groups = $new ;
2021-08-18 22:50:45 +08:00
if ( ! property_exists ( $this , 'Groups' )) {
2020-09-01 06:30:05 +08:00
$this -> Groups = Group :: find ( array ( 'Id' => $this -> GroupIds ()));
}
return $this -> Groups ;
}
2020-09-03 01:56:55 +08:00
function connKey ( $new = '' ) {
2021-08-18 22:50:45 +08:00
if ( $new )
2020-09-03 01:56:55 +08:00
$this -> connKey = $new ;
2021-08-18 22:50:45 +08:00
if ( ! isset ( $this -> connKey )) {
if ( ! empty ( $GLOBALS [ 'connkey' ])) {
2020-09-03 01:56:55 +08:00
$this -> connKey = $GLOBALS [ 'connkey' ];
} else {
$this -> connKey = generateConnKey ();
}
}
return $this -> connKey ;
}
2020-09-01 06:30:05 +08:00
2020-09-18 08:56:04 +08:00
function canEdit () {
global $user ;
return ( $user && ( $user [ 'Monitors' ] == 'Edit' ) && ( ! $this -> { 'Id' } || visibleMonitor ( $this -> { 'Id' }) ));
}
2021-03-12 22:26:23 +08:00
2021-03-30 23:52:04 +08:00
function canView () {
global $user ;
2021-08-15 21:52:48 +08:00
if ( ! $user ) {
2021-08-18 22:50:45 +08:00
# auth turned on and not logged in
return false ;
2021-08-15 21:52:48 +08:00
}
if ( ! empty ( $user [ 'MonitorIds' ]) ) {
# For the purposes of viewing, having specified monitors trumps the Monitor->canView setting.
if ( in_array ( $this -> { 'Id' }, explode ( ',' , $user [ 'MonitorIds' ]))) {
return true ;
}
}
return ( $user [ 'Monitors' ] != 'None' );
2021-03-30 23:52:04 +08:00
}
2021-04-13 03:58:46 +08:00
function AlarmCommand ( $cmd ) {
2021-08-18 22:50:45 +08:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }))) {
2021-04-13 03:58:46 +08:00
switch ( $cmd ) {
case 'on' : $cmd = ' -a' ; break ;
case 'off' : $cmd = ' -c' ; break ;
case 'disable' : $cmd = ' -n' ; break ;
case 'status' : $cmd = ' -s' ; break ;
default :
Warning ( " Invalid command $cmd in AlarmCommand " );
return false ;
}
$cmd = getZmuCommand ( $cmd . ' -m ' . $this -> { 'Id' });
$output = shell_exec ( $cmd );
Debug ( " Running $cmd output: $output " );
return $output ;
}
2021-08-18 22:50:45 +08:00
if ( $this -> ServerId ()) {
2021-04-13 03:58:46 +08:00
$Server = $this -> Server ();
$url = $Server -> UrlToApi () . '/monitors/alarm/id:' . $this -> { 'Id' } . '/command:' . $cmd . '.json' ;
$auth_relay = get_auth_relay ();
if ( $auth_relay ) $url .= '?' . $auth_relay ;
Debug ( 'sending command to ' . $url );
$context = stream_context_create ();
try {
$result = file_get_contents ( $url , false , $context );
2021-08-18 22:50:45 +08:00
if ( $result === FALSE ) { /* Handle error */
2021-04-13 03:58:46 +08:00
Error ( 'Error sending command using ' . $url );
return false ;
}
2021-08-18 22:50:45 +08:00
Debug ( 'Result ' . $result );
2021-04-13 03:58:46 +08:00
$json = json_decode ( $result , true );
return $json [ 'status' ];
2021-08-18 22:50:45 +08:00
} catch ( Exception $e ) {
2021-04-13 03:58:46 +08:00
Error ( " Exception $e thrown trying to send command to $url " );
return false ;
}
} // end if we are on the recording server
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
return false ;
}
2021-03-12 22:26:23 +08:00
function TriggerOn () {
2021-04-13 03:58:46 +08:00
$output = $this -> AlarmCommand ( 'on' );
2021-08-18 22:50:45 +08:00
if ( $output and preg_match ( '/Alarmed event id: (\d+)$/' , $output , $matches )) {
2021-03-12 22:26:23 +08:00
return $matches [ 1 ];
}
2021-08-18 22:50:45 +08:00
Warning ( 'No event returned from TriggerOn' );
2021-03-12 22:26:23 +08:00
}
function TriggerOff () {
2021-04-13 03:58:46 +08:00
$output = $this -> AlarmCommand ( 'off' );
2021-03-12 22:26:23 +08:00
}
2021-04-13 03:18:49 +08:00
function DisableAlarms () {
2021-04-13 03:58:46 +08:00
$output = $this -> AlarmCommand ( 'disable' );
2021-04-13 03:18:49 +08:00
}
2021-07-07 21:46:36 +08:00
function Model () {
2021-09-25 22:32:04 +08:00
if ( ! property_exists ( $this , 'Model' )) {
if ( $this -> { 'ModelId' }) {
$this -> { 'Model' } = Model :: find_one ( array ( 'Id' => $this -> ModelId ()));
if ( ! $this -> { 'Model' })
$this -> { 'Model' } = new Model ();
} else {
$this -> { 'Model' } = new Model ();
}
2021-07-07 21:46:36 +08:00
}
return $this -> { 'Model' };
}
function Manufacturer () {
2021-09-25 22:32:04 +08:00
if ( ! property_exists ( $this , 'Manufacturer' )) {
if ( $this -> { 'ManufacturerId' }) {
$this -> { 'Manufacturer' } = Manufacturer :: find_one ( array ( 'Id' => $this -> ManufacturerId ()));
if ( ! $this -> { 'Manufacturer' })
$this -> { 'Manufacturer' } = new Manufacturer ();
} else {
$this -> { 'Manufacturer' } = new Manufacturer ();
}
2021-07-07 21:46:36 +08:00
}
return $this -> { 'Manufacturer' };
}
2017-10-24 08:00:59 +08:00
} // end class Monitor
2015-09-18 03:29:36 +08:00
?>