diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index efbccf30f..0ab20d162 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -28,29 +28,13 @@ use 5.006; use strict; use warnings; -require Exporter; require ZoneMinder::Base; +require ZoneMinder::Object; +require ZoneMinder::Storage; +require ZoneMinder::Server; -our @ISA = qw(Exporter ZoneMinder::Base); - -# Items to export into callers namespace by default. Note: do not export -# names by default without a very good reason. Use EXPORT_OK instead. -# Do not simply export all your public functions/methods/constants. - -# This allows declaration use ZoneMinder ':all'; -# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK -# will save memory. -our %EXPORT_TAGS = ( - 'functions' => [ qw( - ) ] -); -push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; - -our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); - -our @EXPORT = qw(); - -our $VERSION = $ZoneMinder::Base::VERSION; +#our @ISA = qw(Exporter ZoneMinder::Base); +use parent qw(ZoneMinder::Object); # ========================================================================== # @@ -61,39 +45,11 @@ our $VERSION = $ZoneMinder::Base::VERSION; use ZoneMinder::Config qw(:all); use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); -require ZoneMinder::Server; -require ZoneMinder::Storage; use POSIX; - -sub new { - my ( $parent, $id, $data ) = @_; - - my $self = {}; - bless $self, $parent; - if ( ( $$self{Id} = $id ) or $data ) { -#$log->debug("loading $parent $id") if $debug or DEBUG_ALL; - $self->load( $data ); - } - return $self; -} # end sub new - -sub load { - my ( $self, $data ) = @_; - my $type = ref $self; - if ( ! $data ) { -#$log->debug("Object::load Loading from db $type"); - $data = $ZoneMinder::Database::dbh->selectrow_hashref( 'SELECT * FROM Monitors WHERE Id=?', {}, $$self{Id} ); - if ( ! $data ) { - if ( $ZoneMinder::Database::dbh->errstr ) { - Error( "Failure to load Monitor record for $$self{id}: Reason: " . $ZoneMinder::Database::dbh->errstr ); - } # end if - } # end if - } # end if ! $data - if ( $data and %$data ) { - @$self{keys %$data} = values %$data; - } # end if -} # end sub load +use vars qw/ $table $primary_key /; +$table = 'Monitors'; +$primary_key = 'Id'; sub Server { return new ZoneMinder::Server( $_[0]{ServerId} ); diff --git a/web/includes/Event.php b/web/includes/Event.php index e368d8e89..430c64202 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -73,7 +73,7 @@ class Event { } - public function LinkPath() { + public function Link_Path() { if ( ZM_USE_DEEP_STORAGE ) { return $this->{'MonitorId'} .'/'.strftime( "%y/%m/%d/.", $this->Time()).$this->{'Id'}; } @@ -82,6 +82,7 @@ class Event { } public function delete() { + # This wouldn't work with foreign keys dbQuery( 'DELETE FROM Events WHERE Id = ?', array($this->{'Id'}) ); if ( !ZM_OPT_FAST_DELETE ) { dbQuery( 'DELETE FROM Stats WHERE EventId = ?', array($this->{'Id'}) ); @@ -90,15 +91,28 @@ class Event { # Assumption: All events haev a start time $start_date = date_parse( $this->{'StartTime'} ); + if ( ! $start_date ) { + Error("Unable to parse start time for event " . $this->{'Id'} . ' not deleting files.' ); + return; + } $start_date['year'] = $start_date['year'] % 100; $Storage = $this->Storage(); # So this is because ZM creates a link under teh day pointing to the time that the event happened. + if ( ! $this->Link_Path() ) { + Error("Unable to determine link path for event " . $this->{'Id'} . ' not deleting files.' ); + return; + } + $eventlink_path = $Storage->Path().'/'.$this->Link_Path(); if ( $id_files = glob( $eventlink_path ) ) { + if ( ! $eventPath = readlink($id_files[0]) ) { + Error("Unable to read link at $id_files[0]"); + return; + } # I know we are using arrays here, but really there can only ever be 1 in the array - $eventPath = preg_replace( '/\.'.$event['Id'].'$/', readlink($id_files[0]), $id_files[0] ); + $eventPath = preg_replace( '/\.'.$this->{'Id'}.'$/', $eventPath, $id_files[0] ); deletePath( $eventPath ); deletePath( $id_files[0] ); $pathParts = explode( '/', $eventPath ); @@ -118,7 +132,7 @@ class Event { } # ! ZM_OPT_FAST_DELETE } # end Event->delete -public function getStreamSrc( $args, $querySep='&' ) { + public function getStreamSrc( $args, $querySep='&' ) { return ( ZM_BASE_PATH != '/' ? ZM_BASE_PATH : '' ).'/index.php?view=view_video&eid='.$this->{'Id'}; $streamSrc = ZM_BASE_URL.ZM_PATH_ZMS; diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 546cb9cbe..e5814ef61 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -1,51 +1,74 @@ $v) { - $this->{$k} = $v; - } - } else { - $this->{'Name'} = ''; - $this->{'Path'} = ''; - } + public function __construct( $IdOrRow = NULL ) { + $row = NULL; + if ( $IdOrRow ) { + if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) { + $row = dbFetchOne( 'SELECT * FROM Storage WHERE Id=?', NULL, array( $IdOrRow ) ); + if ( ! $row ) { + Error("Unable to load Storage record for Id=" . $IdOrRow ); + } + } elseif ( is_array( $IdOrRow ) ) { + $row = $IdOrRow; + } } + if ( $row ) { + foreach ($row as $k => $v) { + $this->{$k} = $v; + } + } else { + $this->{'Name'} = ''; + $this->{'Path'} = ''; + } + } - public function Path() { - if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) { - return $this->{'Path'}; - } else if ( ! isset($this->{'Id'}) ) { - return ZM_DIR_EVENTS; - } - return $this->{'Name'}; - } - public function __call( $fn, array $args= NULL){ - if(isset($this->{$fn})){ - return $this->{$fn}; - #array_unshift($args, $this); - #call_user_func_array( $this->{$fn}, $args); - } + public function Path() { + if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) { + return $this->{'Path'}; + } else if ( ! isset($this->{'Id'}) ) { + return ZM_DIR_EVENTS; } - public static function find_all() { - $storage_areas = array(); - $result = dbQuery( 'SELECT * FROM Storage ORDER BY Name'); - $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' ); - foreach ( $results as $row => $obj ) { - $storage_areas[] = $obj; - } - return $storage_areas; + return $this->{'Name'}; + } + public function Name() { + if ( isset( $this->{'Name'} ) and ( $this->{'Name'} != '' ) ) { + return $this->{'Name'}; + } else if ( ! isset($this->{'Id'}) ) { + return 'Default'; } + return $this->{'Name'}; + } + + public function __call( $fn, array $args= NULL){ + if(isset($this->{$fn})){ + return $this->{$fn}; +#array_unshift($args, $this); +#call_user_func_array( $this->{$fn}, $args); + } + } + public static function find_all() { + $storage_areas = array(); + $result = dbQuery( 'SELECT * FROM Storage ORDER BY Name'); + $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' ); + foreach ( $results as $row => $obj ) { + $storage_areas[] = $obj; + } + return $storage_areas; + } + public function disk_usage_percent() { + $path = $this->Path(); + $total = disk_total_space( $path ); + if ( ! $total ) { + Error("disk_total_space returned false for " . $path ); + return 0; + } + $free = disk_free_space( $path ); + if ( ! $free ) { + Error("disk_free_space returned false for " . $path ); + } + $usage = round(($total - $free) / $total * 100); + return $usage; + } } ?> diff --git a/web/includes/actions.php b/web/includes/actions.php index 09b43696b..6b94b7c68 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -124,36 +124,31 @@ if ( !empty($action) ) { } // Event scope actions, view permissions only required - if ( canView( 'Events' ) ) - { - if ( $action == "filter" ) - { - if ( !empty($_REQUEST['subaction']) ) - { + if ( canView( 'Events' ) ) { + + if ( $action == 'filter' ) { + if ( !empty($_REQUEST['subaction']) ) { if ( $_REQUEST['subaction'] == "addterm" ) $_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] ); elseif ( $_REQUEST['subaction'] == "delterm" ) $_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] ); - } - elseif ( canEdit( 'Events' ) ) - { - if ( !empty($_REQUEST['execute']) ) - $tempFilterName = "_TempFilter".time(); - if ( isset($tempFilterName) ) { - $filterName = $tempFilterName; - } - elseif ( !empty($_REQUEST['newFilterName']) ) { + } elseif ( canEdit( 'Events' ) ) { + $sql = ''; + $endSql = ''; + $filterName = ''; + if ( !empty($_REQUEST['execute']) ) { + // TempFilterName is used in event listing later on + $tempFilterName = $filterName = "_TempFilter".time(); + } elseif ( !empty($_REQUEST['newFilterName']) ) { $filterName = $_REQUEST['newFilterName']; - $sql = "replace into Filters set Name = ".dbEscape($filterName).","; - $endSql = ''; } - else { - $doUpdate = 1; - $sql = "update Filters set"; - $endSql = "where Id = ".$_REQUEST['filterId']; + if ( $filterName ) { + $sql = "REPLACE INTO Filters SET Name = ".dbEscape($filterName).","; + } else { + $sql = 'UPDATE Filters SET'; + $endSql = "where Id = ".$_REQUEST['Id']; } - if ( !empty($filterName) || $doUpdate ) - { + if ( !empty($filterName) || $endSql ) { $_REQUEST['filter']['sort_field'] = validStr($_REQUEST['sort_field']); $_REQUEST['filter']['sort_asc'] = validStr($_REQUEST['sort_asc']); $_REQUEST['filter']['limit'] = validInt($_REQUEST['limit']); @@ -180,9 +175,9 @@ if ( !empty($action) ) { dbQuery( $sql ); $refreshParent = true; } - } - } - } + } // end if canedit events + } // end if action == filter + } // end if canview events // Event scope actions, edit permissions required if ( canEdit( 'Events' ) ) @@ -223,17 +218,18 @@ if ( !empty($action) ) { } } } - elseif ( $action == "delete" ) + elseif ( $action == 'delete' ) { foreach( getAffectedIds( 'markEid' ) as $markEid ) { deleteEvent( $markEid ); $refreshParent = true; } - if ( !empty($_REQUEST['fid']) ) - { - dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['filterId'] ) ); - //$refreshParent = true; + if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) { + if ( !empty($_REQUEST['Id']) ) { + dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) ); + //$refreshParent = true; + } } } } diff --git a/web/includes/functions.php b/web/includes/functions.php index 2b97456f7..a3e3834dc 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -450,6 +450,7 @@ function getEventDefaultVideoPath( $event ) { } function deletePath( $path ) { +Error("deletePath $path"); if ( is_dir( $path ) ) { system( escapeshellcmd( "rm -rf ".$path ) ); } else { @@ -1220,6 +1221,8 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { $filter['sql'] = ''; $filter['fields'] = ''; + $StorageArea = NULL; + if ( isset($filter['terms']) && count($filter['terms']) ) { for ( $i = 0; $i < count($filter['terms']); $i++ ) { if ( isset($filter['terms'][$i]['cnj']) ) { @@ -1270,10 +1273,27 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { $filter['sql'] .= 'E.'.$filter['terms'][$i]['attr']; break; case 'DiskPercent': - $filter['sql'] .= getDiskPercent(); + // Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH + if ( ! $StorageArea ) { + for ( $j = $i; $j < count($filter['terms']); $j++ ) { + if ( isset($filter['terms'][$i]['attr']) and $filter['terms'][$i]['attr'] == 'StorageId' ) { + $StorageArea = new Storage( $filter['terms'][$i]['val'] ); + } + } // end foreach remaining term + } // end no StorageArea found yet + + $filter['sql'] .= getDiskPercent( $StorageArea ); break; case 'DiskBlocks': - $filter['sql'] .= getDiskBlocks(); + // Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH + if ( ! $StorageArea ) { + for ( $j = $i; $j < count($filter['terms']); $j++ ) { + if ( isset($filter['terms'][$i]['attr']) and $filter['terms'][$i]['attr'] == 'StorageId' ) { + $StorageArea = new Storage( $filter['terms'][$i]['val'] ); + } + } // end foreach remaining term + } // end no StorageArea found yet + $filter['sql'] .= getDiskBlocks( $StorageArea ); break; case 'SystemLoad': $filter['sql'] .= getLoad(); @@ -1294,6 +1314,10 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { } else { $value = dbEscape($value); } + case 'StorageId': + $StorageArea = new Storage( $value ); + $value = dbEscape($value); + break; case 'DateTime': $value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'"; break; @@ -1460,35 +1484,15 @@ function getLoad() { return( $load[0] ); } -function getDiskPercent() { - if ( !empty(ZM_DIR_EVENTS) ) { - $total = disk_total_space(ZM_DIR_EVENTS); - if ( ! $total ) { - Error("disk_total_space returned false for " . ZM_DIR_EVENTS ); - return 0; - } - $free = disk_free_space(ZM_DIR_EVENTS); - if ( ! $free ) { - Error("disk_free_space returned false for " . ZM_DIR_EVENTS ); - } - $space = round(($total - $free) / $total * 100); - $spaceString = 'Default '.$space.'%'; - } - else { - $spaceString = ''; - } - $storageAreas = Storage::find_all(); - foreach($storageAreas as $storageArea) { - $storageTotal = disk_total_space($storageArea->Path); - $storageFree = disk_free_space($storageArea->Path); - $storageSpace = round(($storageTotal - $storageFree) / $storageTotal * 100); - $spaceString .= ', '.$storageArea->Name.' '.$storageSpace.'%'; - } - return( $spaceString ); +function getDiskPercent( $StorageArea = NULL ) { + if ( ! $StorageArea ) $StorageArea = new Storage(); + + return $StorageArea->disk_usage_percent(); } function getDiskBlocks() { - $df = shell_exec( 'df '.ZM_DIR_EVENTS ); + if ( ! $StorageArea ) $StorageArea = new Storage(); + $df = shell_exec( 'df '.$StorageArea->Path() ); $space = -1; if ( preg_match( '/\s(\d+)\s+\d+\s+\d+%/ms', $df, $matches ) ) $space = $matches[1]; diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 057245de0..42ee5ec52 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -249,7 +249,14 @@ function getNavBarHTML() { diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 4d818a408..93dd66597 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -19,23 +19,26 @@ // if ( !canView( 'Events' ) ) { - $view = "error"; + $view = 'error'; return; } -$selectName = "filterId"; +$selectName = 'Id'; $filterNames = array( ''=>translate('ChooseFilter') ); +$dbFilter = NULL; + foreach ( dbFetchAll( "select * from Filters order by Name" ) as $row ) { $filterNames[$row['Id']] = $row['Name']; if ( $row['Background'] ) $filterNames[$row['Id']] .= "*"; if ( $row['Concurrent'] ) $filterNames[$row['Id']] .= "&"; - if ( !empty($_REQUEST['reload']) && isset($_REQUEST['filterId']) && $_REQUEST['filterId'] == $row['Id'] ) + if ( !empty($_REQUEST['reload']) && isset($_REQUEST['Id']) && $_REQUEST['Id'] == $row['Id'] ) { $dbFilter = $row; + } } -$backgroundStr = ""; -if ( isset($dbFilter) ) { +$backgroundStr = ''; +if ( $dbFilter ) { if ( $dbFilter['Background'] ) $backgroundStr = '['.strtolower(translate('Background')).']'; $_REQUEST['filter'] = jsonDecode( $dbFilter['Query'] ); @@ -57,7 +60,7 @@ if ( isset( $_REQUEST['reload'] ) and ! $_REQUEST['reload'] ) { $dbFilter['AutoUpload'] = isset( $_REQUEST['AutoUpload'] ); $dbFilter['AutoVideo'] = isset( $_REQUEST['AutoVideo'] ); $dbFilter['AutoDelete'] = isset( $_REQUEST['AutoDelete'] ); - $dbFilter['Name'] = $_REQUEST['filterId']; + $dbFilter['Name'] = $_REQUEST['Id']; } $conjunctionTypes = array( @@ -163,7 +166,7 @@ xhtmlHeaders(__FILE__, translate('EventFilter') ); - +
1 ) { echo buildSelect( $selectName, $filterNames, "submitToFilter( this, 1 );" ); } else { ?>