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' );
require_once ( 'Server.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' );
require_once ( 'Storage.php' );
2020-09-01 06:30:05 +08:00
require_once ( 'Group.php' );
$FunctionTypes = null ;
function getMonitorFunctionTypes () {
if ( ! isset ( $FunctionTypes ) ) {
$FunctionTypes = array (
'None' => translate ( 'FnNone' ),
'Monitor' => translate ( 'FnMonitor' ),
'Modect' => translate ( 'FnModect' ),
'Record' => translate ( 'FnMocord' ),
'Nodect' => translate ( 'FnNodect' )
);
}
return $FunctionTypes ;
}
2015-09-18 03:29:36 +08:00
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 ,
2020-04-11 00:16:32 +08:00
'Name' => array ( 'type' => 'text' , 'filter_regexp' => '/[^\w\-\.\(\)\:\/ ]/' ),
2019-12-19 01:13:00 +08:00
'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' => '' ),
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 ,
'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 ,
'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 ,
2019-12-28 23:49:42 +08:00
'ImageBufferCount' => 20 ,
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 ,
'DefaultRate' => 100 ,
'DefaultScale' => 100 ,
'SignalCheckPoints' => 0 ,
'SignalCheckColour' => '#0000BE' ,
2020-01-01 08:10:29 +08:00
'WebColour' => '#ff0000' ,
2019-12-19 01:13:00 +08:00
'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 ,
);
2016-05-06 03:30:24 +08:00
2019-09-20 02:55:27 +08:00
public function Control () {
2019-12-08 00:45:32 +08:00
if ( ! property_exists ( $this , 'Control' ) ) {
2019-09-20 02:55:27 +08:00
if ( $this -> ControlId () )
$this -> { 'Control' } = Control :: find_one ( array ( 'Id' => $this -> { 'ControlId' }));
2019-09-23 09:06:54 +08:00
2019-12-08 00:45:32 +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 () {
2020-01-11 09:13:09 +08:00
if ( ! property_exists ( $this , 'Server' ) ) {
2020-08-25 02:35:59 +08:00
if ( $this -> ServerId () )
2020-01-11 09:15:52 +08:00
$this -> { 'Server' } = Server :: find_one ( array ( 'Id' => $this -> { 'ServerId' }));
2020-01-11 09:13:09 +08:00
if ( ! property_exists ( $this , 'Server' ) ) {
$this -> { 'Server' } = new Server ();
}
}
return $this -> { 'Server' };
2016-05-06 03:30:24 +08:00
}
2019-09-20 02:55:27 +08:00
2017-10-27 09:56:10 +08:00
public function __call ( $fn , array $args ){
if ( count ( $args ) ) {
2019-09-20 02:55:27 +08:00
if ( is_array ( $this -> defaults [ $fn ]) and $this -> defaults [ $fn ][ 'type' ] == 'set' ) {
$this -> { $fn } = is_array ( $args [ 0 ]) ? implode ( ',' , $args [ 0 ]) : $args [ 0 ];
} else {
$this -> { $fn } = $args [ 0 ];
}
2017-06-06 03:21:27 +08:00
}
2019-12-08 00:45:32 +08:00
if ( property_exists ( $this , $fn ) ) {
2016-05-06 03:30:24 +08:00
return $this -> { $fn };
2019-09-20 02:55:27 +08:00
} else if ( array_key_exists ( $fn , $this -> defaults ) ) {
if ( is_array ( $this -> defaults [ $fn ]) ) {
return $this -> defaults [ $fn ][ 'default' ];
}
return $this -> defaults [ $fn ];
} else if ( array_key_exists ( $fn , $this -> status_fields ) ) {
2019-09-24 00:39:24 +08:00
$sql = ' SELECT `Status` , `CaptureFPS` , `AnalysisFPS` , `CaptureBandwidth`
FROM `Monitor_Status` WHERE `MonitorId` = ? ' ;
2019-07-08 05:25:49 +08:00
$row = dbFetchOne ( $sql , NULL , array ( $this -> { 'Id' }));
if ( ! $row ) {
2019-09-20 02:55:27 +08:00
Error ( 'Unable to load Monitor record for Id=' . $this -> { 'Id' });
2019-09-25 22:13:56 +08:00
foreach ( $this -> status_fields as $k => $v ) {
$this -> { $k } = $v ;
}
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
2016-05-06 03:30:24 +08:00
if ( ZM_OPT_USE_AUTH ) {
2017-02-28 10:48:08 +08:00
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
}
}
2020-09-03 01:56:55 +08:00
if ( ( ! isset ( $args [ 'mode' ])) or ( $args [ 'mode' ] != 'single' ) ) {
$args [ 'connkey' ] = $this -> connKey ();
2016-05-06 03:30:24 +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
if ( ! isset ( $args [ 'scale' ]) ) {
if ( isset ( $args [ 'width' ]) and intval ( $args [ 'width' ]) ) {
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'width' ])) / $this -> ViewWidth ());
} else if ( isset ( $args [ 'height' ]) and intval ( $args [ 'height' ]) ) {
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'height' ])) / $this -> ViewHeight ());
2020-07-14 02:50:21 +08:00
}
}
2020-08-27 22:29:50 +08:00
if ( isset ( $args [ 'width' ]) )
unset ( $args [ 'width' ]);
if ( isset ( $args [ 'height' ]) )
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 ) {
2017-10-27 09:56:10 +08:00
if ( $new )
$this -> { 'Width' } = $new ;
2019-11-30 02:56:02 +08:00
$field = ( $this -> Orientation () == 'ROTATE_90' or $this -> Orientation () == 'ROTATE_270' ) ? 'Height' : 'Width' ;
2019-12-08 00:45:32 +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 ) {
2017-10-27 09:56:10 +08:00
if ( $new )
$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' ;
2019-12-08 00:45:32 +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.
2019-12-08 00:45:32 +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
2019-09-09 00:26:11 +08:00
public static function find ( $parameters = array (), $options = array () ) {
return ZM_Object :: _find ( get_class (), $parameters , $options );
2016-05-06 03:30:24 +08:00
}
2017-10-24 08:00:59 +08:00
2019-09-09 00:26:11 +08:00
public static function find_one ( $parameters = array (), $options = array () ) {
return ZM_Object :: _find_one ( get_class (), $parameters , $options );
}
2017-11-06 00:54:00 +08:00
2017-10-24 08:00:59 +08:00
function zmcControl ( $mode = false ) {
2019-09-20 02:55:27 +08:00
if ( ! $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 ;
}
2019-12-08 00:45:32 +08:00
if ( ( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) ) ) {
2019-09-20 02:55:27 +08:00
if ( $this -> Type () == 'Local' ) {
2017-10-24 08:00:59 +08:00
$zmcArgs = '-d ' . $this -> { 'Device' };
} else {
$zmcArgs = '-m ' . $this -> { 'Id' };
}
if ( $mode == 'stop' ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2017-10-24 08:00:59 +08:00
} else {
if ( $mode == 'restart' ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2017-10-24 08:00:59 +08:00
}
2018-01-19 04:38:48 +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
}
2018-01-29 23:27:46 +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' ;
2017-10-24 08:00:59 +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 );
2020-02-26 06:12:48 +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-07-20 22:23:26 +08:00
Logger :: Debug ( 'sending command to ' . $url );
2018-11-15 02:00:19 +08:00
$context = stream_context_create ();
2018-01-19 04:38:48 +08:00
try {
$result = file_get_contents ( $url , false , $context );
2020-08-25 02:35:59 +08:00
if ( $result === FALSE ) { /* Handle error */
2018-01-19 04:38:48 +08:00
Error ( " Error restarting zmc using $url " );
}
} catch ( Exception $e ) {
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
2019-09-20 02:55:27 +08:00
function zmaControl ( $mode = false ) {
2020-07-20 22:23:26 +08:00
if ( ! $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 ;
}
2019-12-08 00:45:32 +08:00
if ( ( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) ) ) {
2017-10-24 08:00:59 +08:00
if ( $this -> { 'Function' } == 'None' || $this -> { 'Function' } == 'Monitor' || $mode == 'stop' ) {
2020-08-25 02:35:59 +08:00
if ( ZM_OPT_CONTROL && $this -> Controllable () && $this -> TrackMotion () &&
2020-07-20 22:23:26 +08:00
( $this -> { 'Function' } == 'Modect' || $this -> { 'Function' } == 'Mocord' ) ) {
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zmtrack.pl' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
}
2018-06-12 04:34:23 +08:00
daemonControl ( 'stop' , 'zma' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
} else {
if ( $mode == 'restart' ) {
if ( ZM_OPT_CONTROL ) {
2019-09-20 02:55:27 +08:00
daemonControl ( 'stop' , 'zmtrack.pl' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
}
2019-09-20 02:55:27 +08:00
daemonControl ( 'stop' , 'zma' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
}
2019-09-20 02:55:27 +08:00
daemonControl ( 'start' , 'zma' , '-m ' . $this -> { 'Id' });
2020-08-25 02:35:59 +08:00
if ( ZM_OPT_CONTROL && $this -> Controllable () && $this -> TrackMotion () &&
2019-09-20 02:55:27 +08:00
( $this -> { 'Function' } == 'Modect' || $this -> { 'Function' } == 'Mocord' ) ) {
daemonControl ( 'start' , 'zmtrack.pl' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
}
if ( $mode == 'reload' ) {
2019-09-20 02:55:27 +08:00
daemonControl ( 'reload' , 'zma' , '-m ' . $this -> { 'Id' });
2017-10-24 08:00:59 +08:00
}
}
2018-11-15 02:00:19 +08:00
} else if ( $this -> ServerId () ) {
$Server = $this -> Server ();
2020-07-21 04:25:29 +08:00
$url = $Server -> UrlToApi () . '/monitors/daemonControl/' . $this -> { 'Id' } . '/' . $mode . '/zma.json' ;
2018-11-15 02:00:19 +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 );
2020-02-26 06:12:48 +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 ;
2018-11-15 02:00:19 +08:00
}
}
Logger :: Debug ( " sending command to $url " );
2020-07-20 22:23:26 +08:00
$context = stream_context_create ();
2018-11-15 02:00:19 +08:00
try {
$result = file_get_contents ( $url , false , $context );
2020-07-20 22:23:26 +08:00
if ( $result === FALSE ) { /* Handle error */
2018-11-15 02:00:19 +08:00
Error ( " Error restarting zma using $url " );
}
} catch ( Exception $e ) {
Error ( " Except $e thrown trying to restart zma " );
}
} else {
2019-09-20 02:55:27 +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 if we are on the recording server
2018-06-12 04:34:23 +08:00
} // end public function zmaControl
2019-09-20 02:55:27 +08:00
public function GroupIds ( $new = '' ) {
2018-04-25 21:27:43 +08:00
if ( $new != '' ) {
2019-09-20 02:55:27 +08:00
if ( ! is_array ( $new ) ) {
2018-04-25 21:27:43 +08:00
$this -> { 'GroupIds' } = array ( $new );
} else {
$this -> { 'GroupIds' } = $new ;
}
}
2019-12-08 00:45:32 +08:00
if ( ! property_exists ( $this , 'GroupIds' ) ) {
if ( property_exists ( $this , 'Id' ) and $this -> { 'Id' } ) {
2019-09-24 00:39:24 +08:00
$this -> { 'GroupIds' } = dbFetchAll ( 'SELECT `GroupId` FROM `Groups_Monitors` WHERE `MonitorId`=?' , 'GroupId' , array ( $this -> { 'Id' }) );
2018-04-25 21:27:43 +08:00
if ( ! $this -> { 'GroupIds' } )
$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 () {
2019-11-02 22:12:43 +08:00
if ( ! $this -> { 'Id' } ) {
Warning ( " Attempt to delete a monitor without id. " );
return ;
}
2018-03-21 03:18:07 +08:00
$this -> zmaControl ( 'stop' );
$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
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
2019-11-02 22:12:43 +08:00
if ( $this -> { 'Name' } )
deletePath ( ZM_DIR_EVENTS . '/' . basename ( $this -> { 'Name' }));
2018-03-21 03:18:07 +08:00
deletePath ( ZM_DIR_EVENTS . '/' . $this -> { 'Id' });
$Storage = $this -> Storage ();
if ( $Storage -> Path () != ZM_DIR_EVENTS ) {
2019-11-02 22:12:43 +08:00
if ( $this -> { 'Name' } )
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' }));
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 ) {
2018-03-22 02:32:54 +08:00
if ( $new ) {
$this -> { 'Storage' } = $new ;
}
2019-12-08 00:45:32 +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 );
2018-05-24 21:54:45 +08:00
if ( ! $this -> { 'Storage' } )
$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 = '' ;
if ( $this -> { 'Type' } == 'Local' ) {
$source = $this -> { 'Device' } . ' (' . $this -> { 'Channel' } . ')' ;
2020-03-30 22:10:06 +08:00
} else if ( $this -> { 'Type' } == 'Remote' ) {
2018-05-04 21:46:46 +08:00
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' } );
if ( $this -> { 'Port' } != '80' and $this -> { 'Port' } != '554' ) {
$source .= ':' . $this -> { 'Port' };
}
2020-03-30 22:10:06 +08:00
} else if ( $this -> { 'Type' } == 'VNC' ) {
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' } );
if ( $this -> { 'Port' } != '5900' ) {
$source .= ':' . $this -> { 'Port' };
}
} else if ( $this -> { 'Type' } == 'Ffmpeg' || $this -> { 'Type' } == 'Libvlc' || $this -> { 'Type' } == 'WebSite' ) {
2018-05-04 21:46:46 +08:00
$url_parts = parse_url ( $this -> { 'Path' } );
2018-11-22 23:04:33 +08:00
if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) {
# Filter out everything but the hostname
2018-09-15 02:26:45 +08:00
if ( isset ( $url_parts [ 'host' ]) ) {
$source = $url_parts [ 'host' ];
} else {
$source = $this -> { 'Path' };
}
2020-03-30 22:10:06 +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']);
if ( isset ( $url_parts [ 'port' ]) and ( $url_parts [ 'port' ] == '80' or $url_parts [ 'port' ] == '554' ) )
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
}
if ( $source == '' ) {
$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 );
2019-03-02 06:25:17 +08:00
//ZM_MIN_STREAMING_PORT ? (ZM_MIN_STREAMING_PORT+$this->Id()) : null);
2018-09-15 02:26:45 +08:00
}
2018-09-08 04:31:11 +08:00
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
$options = array ();
# Convert from a command line params to an option array
foreach ( explode ( ' ' , $command ) as $option ) {
if ( preg_match ( '/--([^=]+)(?:=(.+))?/' , $option , $matches ) ) {
$options [ $matches [ 1 ]] = $matches [ 2 ] ? $matches [ 2 ] : 1 ;
2020-07-20 22:23:26 +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
}
2020-01-01 01:42:49 +08:00
if ( ! count ( $options ) ) {
2020-04-30 04:30:59 +08:00
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
# These are special as we now run zmcontrol as a daemon through zmdc.
$status = daemonStatus ( 'zmcontrol.pl' , array ( '--id' , $this -> { 'Id' }));
Logger :: Debug ( " Current status $status " );
if ( $status or ( ( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) ) ) ) {
daemonControl ( $command , 'zmcontrol.pl' , '--id ' . $this -> { 'Id' });
return ;
}
$options [ 'command' ] = $command ;
2020-01-01 01:42:49 +08:00
} else {
Warning ( " No commands to send to zmcontrol from $command " );
return false ;
}
2019-10-09 06:07:33 +08:00
}
2020-01-01 01:42:49 +08:00
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 ));
$optionString = jsonEncode ( $options );
Logger :: Debug ( " Trying to send options $optionString " );
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
$socket = socket_create ( AF_UNIX , SOCK_STREAM , 0 );
if ( $socket < 0 ) {
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' ;
if ( @ socket_connect ( $socket , $sockFile ) ) {
if ( ! socket_write ( $socket , $optionString ) ) {
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
}
} else if ( $command != 'quit' ) {
$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 );
} 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' ;
2019-10-09 06:07:33 +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 );
2019-10-09 06:07:33 +08:00
} else if ( ZM_AUTH_RELAY == 'plain' ) {
2020-04-30 04:30:59 +08:00
$url .= '?user=' . $_SESSION [ 'username' ];
$url .= '?pass=' . $_SESSION [ 'password' ];
2019-10-09 06:07:33 +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
}
}
Logger :: Debug ( " sending command to $url " );
$context = stream_context_create ();
try {
$result = file_get_contents ( $url , false , $context );
2020-03-27 01:57:00 +08:00
if ( $result === FALSE ) { /* Handle error */
Error ( " Error sending command using $url " );
2019-10-09 06:07:33 +08:00
return false ;
}
} 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 = '' ) {
if ( $new != '' )
$this -> Groups = $new ;
if ( ! property_exists ( $this , 'Groups' ) ) {
$this -> Groups = Group :: find ( array ( 'Id' => $this -> GroupIds ()));
}
return $this -> Groups ;
}
2020-09-03 01:56:55 +08:00
function connKey ( $new = '' ) {
if ( $new )
$this -> connKey = $new ;
if ( ! isset ( $this -> connKey ) ) {
if ( ! empty ( $GLOBALS [ 'connkey' ]) ) {
$this -> connKey = $GLOBALS [ 'connkey' ];
} else {
$this -> connKey = generateConnKey ();
}
}
return $this -> connKey ;
}
2020-09-01 06:30:05 +08:00
2017-10-24 08:00:59 +08:00
} // end class Monitor
2015-09-18 03:29:36 +08:00
?>