From 0bb672b86bae49c943d184801b186bc7584af27f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 10 Sep 2018 17:10:39 -0400 Subject: [PATCH 01/92] dick around reverting ffmpeg 3.4 deprecations to try to get fps correct --- src/zm_ffmpeg.cpp | 19 +++++++------ src/zm_ffmpeg_camera.cpp | 58 ++++++++++++++++++---------------------- src/zm_videostore.cpp | 34 ++++++++++++++++------- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index ac841f27b..4ad06762e 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -273,12 +273,15 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) /* the pid is an important information, so we display it */ /* XXX: add a generic system */ if (flags & AVFMT_SHOW_IDS) - Debug(1, "[0x%x]", st->id); + Debug(1, "ids [0x%x]", st->id); if (lang) - Debug(1, "(%s)", lang->value); - Debug(1, ", frames:%d, timebase: %d/%d", st->codec_info_nb_frames, st->time_base.num, st->time_base.den); + Debug(1, "lang:%s", lang->value); + Debug(1, "frames:%d, stream timebase: %d/%d codec timebase: %d/%d", + st->codec_info_nb_frames, st->time_base.num, st->time_base.den, + st->codec->time_base.num, st->codec->time_base.den + ); avcodec_string(buf, sizeof(buf), st->codec, is_output); - Debug(1, ": %s", buf); + Debug(1, "codec: %s", buf); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) AVCodecParameters *codec = st->codecpar; #else @@ -302,13 +305,10 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) int tbn = st->time_base.den && st->time_base.num; int tbc = st->codec->time_base.den && st->codec->time_base.num; - if (fps || tbn || tbc) - Debug(3, "\n" ); - if (fps) - zm_log_fps(av_q2d(st->avg_frame_rate), tbn || tbc ? "fps, " : "fps"); + zm_log_fps(av_q2d(st->avg_frame_rate), "fps"); if (tbn) - zm_log_fps(1 / av_q2d(st->time_base), tbc ? "stream tb numerator , " : "stream tb numerator"); + zm_log_fps(1 / av_q2d(st->time_base), "stream tb numerator"); if (tbc) zm_log_fps(1 / av_q2d(st->codec->time_base), "codec time base:"); } @@ -333,7 +333,6 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) Debug(1, " (visual impaired)"); if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) Debug(1, " (clean effects)"); - Debug(1, "\n"); //dump_metadata(NULL, st->metadata, " "); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 2622f5dfa..2a00c601c 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -437,11 +437,13 @@ int FfmpegCamera::OpenFfmpeg() { Debug(3, "Found audio stream at index %d", mAudioStreamId); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - mVideoCodecContext = avcodec_alloc_context3(NULL); - avcodec_parameters_to_context( mVideoCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar ); + //mVideoCodecContext = avcodec_alloc_context3(NULL); + //avcodec_parameters_to_context( mVideoCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar ); + // this isn't copied. + //mVideoCodecContext->time_base = mFormatContext->streams[mVideoStreamId]->codec->time_base; #else - mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec; #endif + mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec; // STolen from ispy //this fixes issues with rtsp streams!! woot. //mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode. @@ -484,16 +486,6 @@ int FfmpegCamera::OpenFfmpeg() { } } } - } else { -#ifdef AV_CODEC_ID_H265 - if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { - Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); - } else { -#endif - Warning( "Input stream is not h264. The stored event file may not be viewable in browser." ); -#ifdef AV_CODEC_ID_H265 - } -#endif } // end if h264 #endif if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { @@ -511,29 +503,30 @@ int FfmpegCamera::OpenFfmpeg() { } else { Debug(1, "Video Found decoder %s", mVideoCodec->name); zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); - // Open the codec + // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - Debug ( 1, "Calling avcodec_open" ); - if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ){ + Debug(1, "Calling avcodec_open"); + if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ) #else - Debug ( 1, "Calling avcodec_open2" ); - if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) { + Debug(1, "Calling avcodec_open2"); + if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) #endif - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); - } - Error( "Unable to open codec for video stream from %s", mPath.c_str() ); - av_dict_free(&opts); - return -1; - } else { + { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Option %s not recognized by ffmpeg", e->key); + } + Error( "Unable to open codec for video stream from %s", mPath.c_str() ); + av_dict_free(&opts); + return -1; + } else { - AVDictionaryEntry *e = NULL; - if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); + AVDictionaryEntry *e = NULL; + if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Option %s not recognized by ffmpeg", e->key); + } + av_dict_free(&opts); } - av_dict_free(&opts); - } } if (mVideoCodecContext->hwaccel != NULL) { @@ -653,8 +646,9 @@ int FfmpegCamera::Close() { if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); + Debug(1,"After codec close"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&mVideoCodecContext); + //avcodec_free_context(&mVideoCodecContext); #endif mVideoCodecContext = NULL; // Freed by av_close_input_file } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 7db4906ca..b4e1db494 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -39,13 +39,13 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_in_stream = p_audio_in_stream; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_ctx = avcodec_alloc_context3(NULL); - avcodec_parameters_to_context(video_in_ctx, - video_in_stream->codecpar); + //video_in_ctx = avcodec_alloc_context3(NULL); + //avcodec_parameters_to_context(video_in_ctx, + //video_in_stream->codecpar); // zm_dump_codecpar( video_in_stream->codecpar ); #else - video_in_ctx = video_in_stream->codec; #endif + video_in_ctx = video_in_stream->codec; // store ins in variables local to class filename = filename_in; @@ -85,7 +85,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, oc->metadata = pmetadata; out_format = oc->oformat; -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) +#if 0 + //LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Since we are not re-encoding, all we have to do is copy the parameters video_out_ctx = avcodec_alloc_context3(NULL); @@ -159,6 +160,20 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, // Just copy them from the in, no reason to choose different video_out_ctx->time_base = video_in_ctx->time_base; video_out_stream->time_base = video_in_stream->time_base; + if ( video_in_stream->avg_frame_rate.num ) { + Debug(3,"Copying avg_frame_rate (%d/%d)", + video_in_stream->avg_frame_rate.num, + video_in_stream->avg_frame_rate.den + ); + video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate; + } + if ( video_in_stream->r_frame_rate.num ) { + Debug(3,"Copying r_frame_rate (%d/%d)", + video_in_stream->r_frame_rate.num, + video_in_stream->r_frame_rate.den + ); + video_out_stream->r_frame_rate = video_in_stream->r_frame_rate; + } Debug(3, "Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out " @@ -166,8 +181,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_in_stream->time_base.num, video_in_stream->time_base.den, video_in_ctx->time_base.num, video_in_ctx->time_base.den, video_out_stream->time_base.num, video_out_stream->time_base.den, - video_out_ctx->time_base.num, - video_out_ctx->time_base.den); + video_out_ctx->time_base.num, video_out_ctx->time_base.den); if (oc->oformat->flags & AVFMT_GLOBALHEADER) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) @@ -324,7 +338,7 @@ bool VideoStore::open() { AVDictionary *opts = NULL; // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); if ((ret = avformat_write_header(oc, &opts)) < 0) { @@ -435,13 +449,13 @@ VideoStore::~VideoStore() { if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&video_in_ctx); + //avcodec_free_context(&video_in_ctx); #endif video_in_ctx = NULL; avcodec_close(video_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&video_out_ctx); + //avcodec_free_context(&video_out_ctx); #endif video_out_ctx = NULL; Debug(4, "Success freeing video_out_ctx"); From dca9a81cfdea0feb57a64f8a2a6b9d36f384fc26 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Feb 2019 16:45:05 -0500 Subject: [PATCH 02/92] implement data-on-click-true --- web/skins/classic/js/skin.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 4b1f47717..c78853608 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -173,6 +173,14 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { }; }); + // 'data-on-click-true' calls the global function in the attribute value with no arguments when a click happens. + document.querySelectorAll("a[data-on-click-true], button[data-on-click-true], input[data-on-click-true]").forEach(function attachOnClick(el) { + var fnName = el.getAttribute("data-on-click-true"); + el.onclick = function() { + window[fnName](true); + }; + }); + // 'data-on-change-this' calls the global function in the attribute value with the element when a change happens. document.querySelectorAll("select[data-on-change-this], input[data-on-change-this]").forEach(function attachOnChangeThis(el) { var fnName = el.getAttribute("data-on-change-this"); @@ -256,7 +264,7 @@ if ( currentView != 'none' && currentView != 'login' ) { $j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON. $j(document).ready(function() { - if ($j('.navbar').length) { + if ( $j('.navbar').length ) { setInterval(getNavBar, navBarRefresh); } }); @@ -264,12 +272,12 @@ if ( currentView != 'none' && currentView != 'login' ) { function getNavBar() { $j.getJSON(thisUrl + '?view=request&request=status&entity=navBar') .done(setNavBar) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed: " + textStatus + ", " + error); + .fail(function(jqxhr, textStatus, error) { + console.log("Request Failed: " + textStatus + ", " + error); if ( textStatus != "timeout" ) { // The idea is that this should only fail due to auth, so reload the page // which should go to login if it can't stay logged in. - window.location.reload( true ); + window.location.reload(true); } }); } From 8e62c93f5f7ea65476176d993411a2ad03f7c528 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 11:44:36 -0500 Subject: [PATCH 03/92] add to_json function to Storage. --- web/includes/Storage.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 95f1dab84..a7372b15a 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -223,5 +223,19 @@ class Storage { } return $this->{'Server'}; } + + public function to_json() { + $json = array(); + foreach ($this->defaults as $key => $value) { + if ( is_callable(array($this, $key)) ) { + $json[$key] = $this->$key(); + } else if ( array_key_exists($key, $this) ) { + $json[$key] = $this->{$key}; + } else { + $json[$key] = $this->defaults{$key}; + } + } + return json_encode($json); + } } ?> From edaf582eb49b70d340b828349e046a154d731ed0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 11:46:48 -0500 Subject: [PATCH 04/92] Make montagereview more robust when the storage area of an event has been deleted. Add the onmouse events using javascript instead of in the html canvas element so that our CSP policy works. --- web/skins/classic/views/js/montagereview.js | 18 ++++++++++++++++-- .../classic/views/js/montagereview.js.php | 12 ++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index ccdea0a07..adb285f48 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -122,6 +122,11 @@ function getImageSource( monId, time ) { Event = events[Frame.EventId]; var storage = Storage[Event.StorageId]; + if ( ! storage ) { + // Storage[0] is guaranteed to exist as we make sure it is there in montagereview.js.php + console.log("No storage area for id " + Event.StorageId); + storage = Storage[0]; + } // monitorServerId may be 0, which gives us the default Server entry var server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]]; return server.PathToIndex + @@ -500,7 +505,8 @@ HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords; var mouseisdown=false; function mdown(event) { - mouseisdown=true; mmove(event); + mouseisdown=true; + mmove(event); } function mup(event) { mouseisdown=false; @@ -509,7 +515,8 @@ function mout(event) { mouseisdown=false; } // if we go outside treat it as release function tmove(event) { - mouseisdown=true; mmove(event); + mouseisdown=true; + mmove(event); } function mmove(event) { @@ -910,6 +917,13 @@ function initPage() { } if ( !liveMode ) { canvas = $("timeline"); + + canvas.addEventListener('mousemove', mmove, false); + canvas.addEventListener('touchmove', tmove, false); + canvas.addEventListener('mousedown', mdown, false); + canvas.addEventListener('mouseup', mup, false); + canvas.addEventListener('mouseout', mout, false); + ctx = canvas.getContext('2d'); drawGraph(); } diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index a31bbfa9e..c887bb0e3 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -119,13 +119,21 @@ echo " };\n"; } // end if initialmodeislive echo "\nvar Storage = [];\n"; +$have_storage_zero = 0; foreach ( Storage::find() as $Storage ) { - echo 'Storage[' . $Storage->Id() . '] = ' . json_encode($Storage). ";\n"; + echo 'Storage[' . $Storage->Id() . '] = ' . $Storage->to_json(). ";\n"; + if ( $Storage->Id() == 0 ) + $have_storage_zero = true; } +if ( !$have_storage_zero ) { + $Storage = new Storage(); + echo 'Storage[0] = ' . $Storage->to_json(). ";\n"; +} + echo "\nvar Servers = [];\n"; // Fall back to get Server paths, etc when no using multi-server mode $Server = new Server(); -echo 'Servers[0] = new Server(' . json_encode($Server). ");\n"; +echo 'Servers[0] = new Server(' . $Server->to_json(). ");\n"; foreach ( Server::find() as $Server ) { echo 'Servers[' . $Server->Id() . '] = new Server(' . $Server->to_json(). ");\n"; } From 6744a9a11671b5b61e7d208e5a35ad248b702417 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 11:46:55 -0500 Subject: [PATCH 05/92] Make montagereview more robust when the storage area of an event has been deleted. Add the onmouse events using javascript instead of in the html canvas element so that our CSP policy works. --- web/skins/classic/views/montagereview.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 039938824..8e1ccdb9b 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -290,7 +290,7 @@ if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
- + From b04b67c39d526c955499a403b89c4dc1722263f1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 12:17:10 -0500 Subject: [PATCH 06/92] Fix CSP violation in the onclick of the monitor view in montagereview --- web/skins/classic/views/js/montagereview.js | 23 +++++++++++++++------ web/skins/classic/views/montagereview.php | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index adb285f48..b50d59996 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -842,13 +842,15 @@ function zoom(monId, scale) { } } -function clickMonitor(event, monId) { - var monitor_element = $("Monitor"+monId.toString()); - var pos_x = event.offsetX ? (event.offsetX) : event.pageX - monitor_element.offsetLeft; - var pos_y = event.offsetY ? (event.offsetY) : event.pageY - monitor_element.offsetTop; - if ( pos_x < monitor_element.width/4 && pos_y < monitor_element.height/4 ) { +function clickMonitor(event) { + var element = event.target; + //var monitor_element = $("Monitor"+monId.toString()); + var monId = element.getAttribute('monitor_id'); + var pos_x = event.offsetX ? (event.offsetX) : event.pageX - element.offsetLeft; + var pos_y = event.offsetY ? (event.offsetY) : event.pageY - element.offsetTop; + if ( pos_x < element.width/4 && pos_y < element.height/4 ) { zoom(monId, 1.15); - } else if ( pos_x > monitor_element.width * 3/4 && pos_y < monitor_element.height/4 ) { + } else if ( pos_x > element.width * 3/4 && pos_y < element.height/4 ) { zoom(monId, 1/1.15); } else { showOneMonitor(monId); @@ -927,6 +929,15 @@ function initPage() { ctx = canvas.getContext('2d'); drawGraph(); } + for ( i=0, len=monitorPtr.length; i < len; i += 1 ) { + var monitor_id = monitorPtr[i]; + monitor_canvas = $('Monitor'+monitor_id); + if ( ! monitor_canvas ) { + console.log("No canvas found for monitor " + monitor_id); + continue; + } + monitor_canvas.addEventListener('click',clickMonitor,false); + } setSpeed(speedIndex); //setFit(fitMode); // will redraw //setLive(liveMode); // will redraw diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 8e1ccdb9b..a822febbe 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -304,8 +304,8 @@ if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" onclick="clickMonitor(event,' . $m->Id() . ')">No Canvas Support!!'; + foreach ( $monitors as $m ) { + echo 'No Canvas Support!!'; } ?>
From 0783802d0cb625b8b501ac2471f336192d44ea04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 13:31:34 -0500 Subject: [PATCH 07/92] fix CSP violations on events --- web/skins/classic/views/events.php | 23 ++++++----- web/skins/classic/views/js/events.js | 61 ++++++++++++++++++---------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 885924e64..35a3219aa 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -190,8 +190,8 @@ while ( $event_row = dbFetchNext($results) ) { $scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); ?> Archived()) echo ' class="archived"' ?>> - '.$event->Id().($event->Archived()?'*':'') ?> - '.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?> + '.$event->Id().($event->Archived()?'*':'') ?> + '.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?> MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?> Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?> Notes() && ($event->Notes() != 'Forced Web: ')) echo "
".$event->Notes()."
" ?> @@ -227,12 +227,12 @@ while ( $event_row = dbFetchNext($results) ) { $streamSrc = $event->getStreamSrc(array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single')); - $imgHtml = ''. validHtmlStr('Event '.$event->Id()) .''; + $imgHtml = ''. validHtmlStr('Event '.$event->Id()) .''; echo ''.$imgHtml.''; echo ''; } // end if ZM_WEB_LIST_THUMBS ?> - +
- - - - - - -
@@ -301,6 +301,7 @@ if ( $pagination ) {
diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 9bdabdaef..f105b4cf7 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -17,12 +17,13 @@ function setButtonStates( element ) { form.deleteBtn.disabled = !(canEditEvents && checked); } -function configureButton( element, name ) { +function configureButton(event) { + var element = event.target; var form = element.form; var checked = element.checked; if ( !checked ) { - for (var i = 0; i < form.elements.length; i++) { - if ( form.elements[i].name.indexOf(name) == 0) { + for (var i = 0, len=form.elements.length; i < len; i++) { + if ( form.elements[i].name.indexOf('markEids') == 0) { if ( form.elements[i].checked ) { checked = true; break; @@ -42,15 +43,17 @@ function configureButton( element, name ) { form.deleteBtn.disabled = !(canEditEvents && checked); } -function deleteEvents( element, name ) { +function deleteEvents( element ) { if ( ! canEditEvents ) { alert("You do not have permission to delete events."); return; } var form = element.form; + var count = 0; + // This is slightly more efficient than a jquery selector because we stop after finding one. for (var i = 0; i < form.elements.length; i++) { - if (form.elements[i].name.indexOf(name) == 0) { + if (form.elements[i].name.indexOf('markEids') == 0) { if ( form.elements[i].checked ) { count++; break; @@ -65,15 +68,15 @@ function deleteEvents( element, name ) { } } -function editEvents( element, name ) { +function editEvents( element ) { if ( ! canEditEvents ) { alert("You do not have permission to delete events."); return; } var form = element.form; var eids = new Array(); - for (var i = 0; i < form.elements.length; i++) { - if (form.elements[i].name.indexOf(name) == 0) { + for (var i = 0, len=form.elements.length; i < len; i++) { + if (form.elements[i].name.indexOf('markEids') == 0) { if ( form.elements[i].checked ) { eids[eids.length] = 'eids[]='+form.elements[i].value; } @@ -82,24 +85,24 @@ function editEvents( element, name ) { createPopup( '?view=eventdetail&'+eids.join( '&' ), 'zmEventDetail', 'eventdetail' ); } -function downloadVideo( element, name ) { +function downloadVideo( element ) { var form = element.form; var eids = new Array(); - for (var i = 0; i < form.elements.length; i++) { - if (form.elements[i].name.indexOf(name) == 0) { + for (var i = 0, len=form.elements.length; i < len; i++) { + if (form.elements[i].name.indexOf('markEids') == 0 ) { if ( form.elements[i].checked ) { eids[eids.length] = 'eids[]='+form.elements[i].value; } } } - createPopup( '?view=download&'+eids.join( '&' ), 'zmDownload', 'download' ); + createPopup( '?view=download&'+eids.join('&'), 'zmDownload', 'download' ); } -function exportEvents( element, name ) { +function exportEvents( element ) { var form = element.form; var eids = new Array(); - for (var i = 0; i < form.elements.length; i++) { - if (form.elements[i].name.indexOf(name) == 0) { + for (var i = 0, len=form.elements.length; i < len; i++) { + if (form.elements[i].name.indexOf('markEids') == 0 ) { if ( form.elements[i].checked ) { eids[eids.length] = 'eids[]='+form.elements[i].value; } @@ -108,11 +111,11 @@ function exportEvents( element, name ) { createPopup( '?view=export&'+eids.join( '&' ), 'zmExport', 'export' ); } -function viewEvents( element, name ) { +function viewEvents( element ) { var form = element.form; var events = new Array(); - for (var i = 0; i < form.elements.length; i++) { - if ( form.elements[i].name.indexOf(name) == 0) { + for (var i = 0, len=form.elements.length; i < len; i++) { + if ( form.elements[i].name.indexOf('markEids') == 0 ) { if ( form.elements[i].checked ) { events[events.length] = form.elements[i].value; } @@ -124,13 +127,13 @@ function viewEvents( element, name ) { } } -function archiveEvents( element, name ) { +function archiveEvents(element) { var form = element.form; form.elements['action'].value = 'archive'; form.submit(); } -function unarchiveEvents(element, name) { +function unarchiveEvents(element) { if ( ! canEditEvents ) { alert("You do not have permission to delete events."); return; @@ -146,10 +149,26 @@ if ( openFilterWindow ) { location.replace( '?view='+currentView+'&page='+thisPage+filterQuery ); } +function thumbnail_onmouseover(event) { + var img = event.target; + img.src = img.getAttribute('stream_src'); +} +function thumbnail_onmouseout(event) { + var img = event.target; + img.src = img.getAttribute('still_src'); +} + function initPage() { - if (window.history.length == 1) { + if ( window.history.length == 1 ) { $j('#controls').children().eq(0).html(''); } + $j('.colThumbnail img').each(function(){ + this.addEventListener('mouseover',thumbnail_onmouseover,false); + this.addEventListener('mouseout',thumbnail_onmouseout,false); + }); + $j('input[name=markEids\\[\\]]').each(function(){ + this.addEventListener('click',configureButton,false); + }); } $j(document).ready(initPage); From 7e84a5914c7933bfe2f51a8d77a98e3231a36f2b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Feb 2019 13:55:19 -0500 Subject: [PATCH 08/92] fix CSP policy violations on filters view --- web/skins/classic/views/filter.php | 4 ++-- web/skins/classic/views/js/filter.js | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 403a9b440..fab68941c 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -165,7 +165,7 @@ xhtmlHeaders(__FILE__, translate('EventFilter') );
1 ) { - echo htmlSelect('Id', $filterNames, $filter->Id(), 'this.form.submit();'); + echo htmlSelect('Id', $filterNames, $filter->Id(), array('data-on-change-this'=>'selectFilter')); } else { ?> Id() ) { ?> - + Date: Thu, 7 Feb 2019 08:56:48 -0500 Subject: [PATCH 09/92] fix buttons on events page. data-onclick-this to data-on-click-this --- web/skins/classic/views/events.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 35a3219aa..3beff0188 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -232,7 +232,7 @@ while ( $event_row = dbFetchNext($results) ) { echo ''; } // end if ZM_WEB_LIST_THUMBS ?> - +
- - - - - - -
From ee3a0c1fd112faa74a4dda359122f4d9138872c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 09:55:32 -0500 Subject: [PATCH 10/92] fix validateForm running on monitor cancel due to lack of type=button on cancel button --- web/index.php | 2 +- web/skins/classic/views/js/monitor.js.php | 4 ++-- web/skins/classic/views/monitor.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/index.php b/web/index.php index 5190fad65..40b387c02 100644 --- a/web/index.php +++ b/web/index.php @@ -224,7 +224,7 @@ if ( ZM_OPT_USE_AUTH and !isset($user) ) { Logger::Debug('Redirecting to login'); $view = 'login'; $request = null; -} else if ( ZM_SHOW_PRIVACY && ($action != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { +} else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { Logger::Debug('Redirecting to privacy'); $view = 'privacy'; $request = null; diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 82127dd8e..6bb6f73ff 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -133,9 +133,9 @@ function validateForm( form ) { if ( errors.length ) { alert( errors.join( "\n" ) ); - return( false ); + return false; } - return( true ); + return true; } function updateLinkedMonitors( element ) { diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index af770eb79..59e4ca04f 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -108,8 +108,8 @@ if ( ! $monitor ) { 'EventPrefix' => 'Event-', 'AnalysisFPSLimit' => '', 'AnalysisUpdateDelay' => 0, - 'MaxFPS' => '30', - 'AlarmMaxFPS' => '30', + 'MaxFPS' => null, + 'AlarmMaxFPS' => null, 'FPSReportInterval' => 100, 'RefBlendPerc' => 6, 'AlarmRefBlendPerc' => 6, @@ -1044,7 +1044,7 @@ if ( $monitor->Type() == 'Local' ) {
- +
From e2fc0ea25d521ab1a1120f6b676f411f33546bd2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 10:22:42 -0500 Subject: [PATCH 11/92] Increase navbar refresh times. 5 seconds is way too fast --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index fa7b86079..ff5b6ea33 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -3035,7 +3035,7 @@ our @options = ( }, { name => 'ZM_WEB_H_REFRESH_NAVBAR', - default => '5', + default => '60', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. @@ -3308,7 +3308,7 @@ our @options = ( }, { name => 'ZM_WEB_M_REFRESH_NAVBAR', - default => '15', + default => '120', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. @@ -3581,7 +3581,7 @@ our @options = ( }, { name => 'ZM_WEB_L_REFRESH_NAVBAR', - default => '35', + default => '180', description => 'How often (in seconds) the navigation header should refresh itself', help => q` The navigation header contains the general status information about server load and storage space. From 0eb1efff8b4cfe87efef27776c9cdacb0d8243d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Feb 2019 13:48:38 -0500 Subject: [PATCH 12/92] fix eslint errors --- web/skins/classic/views/js/events.js | 10 +++++----- web/skins/classic/views/js/montagereview.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index f105b4cf7..b594faa20 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -162,12 +162,12 @@ function initPage() { if ( window.history.length == 1 ) { $j('#controls').children().eq(0).html(''); } - $j('.colThumbnail img').each(function(){ - this.addEventListener('mouseover',thumbnail_onmouseover,false); - this.addEventListener('mouseout',thumbnail_onmouseout,false); + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); }); - $j('input[name=markEids\\[\\]]').each(function(){ - this.addEventListener('click',configureButton,false); + $j('input[name=markEids\\[\\]]').each(function() { + this.addEventListener('click', configureButton, false); }); } diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index b50d59996..f21b59baa 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -936,7 +936,7 @@ function initPage() { console.log("No canvas found for monitor " + monitor_id); continue; } - monitor_canvas.addEventListener('click',clickMonitor,false); + monitor_canvas.addEventListener('click', clickMonitor, false); } setSpeed(speedIndex); //setFit(fitMode); // will redraw From 2dc935b488e2935add61bfafefd88230a41b9851 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Fri, 8 Feb 2019 13:49:00 -0500 Subject: [PATCH 13/92] added object detection frame rendering (#2505) --- web/views/image.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/web/views/image.php b/web/views/image.php index d9b740059..baa8b94cb 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -77,7 +77,17 @@ if ( empty($_REQUEST['path']) ) { return; } - if ( $_REQUEST['fid'] == 'alarm' ) { + if ( $_REQUEST['fid'] == 'objdetect' ) { + $Event = new Event($_REQUEST['eid']); + $path = $Event->Path().'/objdetect.jpg'; + unset($Event); # we don't want event object related processing later for this case + if ( !file_exists($path)) { + header('HTTP/1.0 404 Not Found'); + Fatal("File ".$path." does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + } + + } + else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), array('order'=>'FrameId ASC')); @@ -220,6 +230,7 @@ if ( empty($_REQUEST['path']) ) { } } +# we now load the actual image to send $scale = 0; if ( !empty($_REQUEST['scale']) ) { if ( is_numeric($_REQUEST['scale']) ) { From e36ac1b87295f7442054b919694c10d443d64eff Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Fri, 8 Feb 2019 21:54:23 -0800 Subject: [PATCH 14/92] Add a polyfill for NodeList.prototype.forEach --- web/skins/classic/js/skin.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c78853608..3cbb99e49 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -126,6 +126,11 @@ function createPopup( url, name, tag, width, height ) { } } +// Polyfill for NodeList.prototype.forEach on IE. +if (window.NodeList && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = Array.prototype.forEach; +} + window.addEventListener("DOMContentLoaded", function onSkinDCL() { document.querySelectorAll("form.validateFormOnSubmit").forEach(function(el) { el.addEventListener("submit", function onSubmit(evt) { From 0b38e72f882aea7006dac01d3348f2465bcc8c09 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 01:16:32 -0800 Subject: [PATCH 15/92] view=download: Remove inline event handlers and fix arbitrary URL/XSS usage. Fixes #2441 --- web/ajax/event.php | 2 +- web/includes/functions.php | 1 + web/skins/classic/views/download.php | 17 +++++++++++++---- web/skins/classic/views/js/download.js | 5 ++++- web/skins/classic/views/js/download.js.php | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 04ebca9ad..9d8a85438 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -84,7 +84,7 @@ if ( canView( 'Events' ) ) { $exportStructure = 'flat'; $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; if ( $exportFile = exportEvents( $exportIds, false, false, false, $exportVideo, false, $exportFormat, $exportStructure ) ) - ajaxResponse( array( 'exportFile'=>$exportFile ) ); + ajaxResponse( array( 'exportFormat'=>$exportFormat ) ); else ajaxError( 'Export Failed' ); break; diff --git a/web/includes/functions.php b/web/includes/functions.php index a9cf815b4..2a024fe5a 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -53,6 +53,7 @@ function CSPHeaders($view, $nonce) { case 'controlcap': case 'cycle': case 'donate': + case 'download': case 'error': case 'function': case 'log': diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 4cd46ad6f..5535df36a 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -44,6 +44,15 @@ if (isset($_SESSION['montageReviewFilter'])) { //Handles montageReview filter #Logger::Debug("NO montageReviewFilter"); } +$exportFormat = ''; +if (isset($_REQUEST['exportFormat'])) { + if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { + Error("Invalid exportFormat"); + return; + } + $exportFormat = $_REQUEST['exportFormat']; +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Download') ); @@ -88,15 +97,15 @@ if ( !empty($_REQUEST['eid']) ) { - + - + - + - + diff --git a/web/skins/classic/views/js/download.js b/web/skins/classic/views/js/download.js index c5a179466..483f21d5b 100644 --- a/web/skins/classic/views/js/download.js +++ b/web/skins/classic/views/js/download.js @@ -14,7 +14,7 @@ function exportProgress() { } function exportResponse( respObj, respText ) { - window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) ); + window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFormat='+respObj.exportFormat+'&generated='+((respObj.result=='Ok')?1:0) ); } function exportEvent( form ) { @@ -33,6 +33,9 @@ function initPage() { if ( exportReady ) { startDownload.pass( exportFile ).delay( 1500 ); } + document.getElementById('exportButton').addEventListener("click", function onClick(evt) { + exportEvent(this.form); + }); } window.addEventListener( 'DOMContentLoaded', initPage ); diff --git a/web/skins/classic/views/js/download.js.php b/web/skins/classic/views/js/download.js.php index 8e47bd2f6..3501fc711 100644 --- a/web/skins/classic/views/js/download.js.php +++ b/web/skins/classic/views/js/download.js.php @@ -14,6 +14,6 @@ var eidParm = 'eid='; ?> var exportReady = ; -var exportFile = ''; +var exportFile = '?view=archive&type='; var exportProgressString = ''; From 61f6a92cc050f3db831f04c3c19f8f2d52cbe08e Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 01:37:32 -0800 Subject: [PATCH 16/92] view=download: Validate the eid parameter to avoid XSS. Fixes #2442 --- web/skins/classic/views/download.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 5535df36a..cd3b6c71d 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -47,12 +47,20 @@ if (isset($_SESSION['montageReviewFilter'])) { //Handles montageReview filter $exportFormat = ''; if (isset($_REQUEST['exportFormat'])) { if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { - Error("Invalid exportFormat"); + Error('Invalid exportFormat'); return; } $exportFormat = $_REQUEST['exportFormat']; } +if (!empty($_REQUEST['eid'])) { + $Event = new Event( $_REQUEST['eid'] ); + if (!$Event->Id) { + Error('Invalid event id'); + return; + } +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Download') ); @@ -72,8 +80,7 @@ if ( !empty($_REQUEST['eid']) ) { ?> DiskSpace() ); + echo 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() ); } else if ( !empty($_REQUEST['eids']) ) { $total_size = 0; foreach ( $_REQUEST['eids'] as $eid ) { @@ -126,7 +133,7 @@ if ( !empty($_REQUEST['eid']) ) { } if ( !empty($_REQUEST['generated']) ) { ?> - + From 02f09aad7f4ff50f1dd113c964f10d8e675da916 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:01:26 -0800 Subject: [PATCH 17/92] view=export: Remove inline event handlers and fix arbitrary URL/XSS usage. Fixes #2443 --- web/ajax/event.php | 2 +- web/includes/functions.php | 1 + web/skins/classic/views/export.php | 11 +++++++++-- web/skins/classic/views/js/export.js | 5 ++++- web/skins/classic/views/js/export.js.php | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 9d8a85438..4eed2e832 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -71,7 +71,7 @@ if ( canView( 'Events' ) ) { $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; if ( $exportFile = exportEvents( $exportIds, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat ) ) - ajaxResponse( array( 'exportFile'=>$exportFile ) ); + ajaxResponse( array( 'exportFormat'=>$exportFormat ) ); else ajaxError( 'Export Failed' ); break; diff --git a/web/includes/functions.php b/web/includes/functions.php index 2a024fe5a..4aea38a60 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -55,6 +55,7 @@ function CSPHeaders($view, $nonce) { case 'donate': case 'download': case 'error': + case 'export': case 'function': case 'log': case 'logout': diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 0565f6231..d1b5d0413 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -38,6 +38,13 @@ if ( isset($_SESSION['export']) ) { $_REQUEST['exportFormat'] = $_SESSION['export']['format']; } +if (isset($_REQUEST['exportFormat'])) { + if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { + Error('Invalid exportFormat'); + return; + } +} + $focusWindow = true; xhtmlHeaders(__FILE__, translate('Export') ); @@ -97,7 +104,7 @@ if ( !empty($_REQUEST['eid']) ) { - + - + diff --git a/web/skins/classic/views/js/export.js b/web/skins/classic/views/js/export.js index 899256b34..df15a2ef6 100644 --- a/web/skins/classic/views/js/export.js +++ b/web/skins/classic/views/js/export.js @@ -29,7 +29,7 @@ function exportProgress() { } function exportResponse( respObj, respText ) { - window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) ); + window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFormat='+respObj.exportFormat+'&generated='+((respObj.result=='Ok')?1:0) ); } function exportEvent( form ) { @@ -49,6 +49,9 @@ function initPage() { if ( exportReady ) { startDownload.pass( exportFile ).delay( 1500 ); } + document.getElementById('exportButton').addEventListener('click', function onClick() { + exportEvent(this.form); + }); } window.addEventListener( 'DOMContentLoaded', initPage ); diff --git a/web/skins/classic/views/js/export.js.php b/web/skins/classic/views/js/export.js.php index fd9d64dc5..26abb64cf 100644 --- a/web/skins/classic/views/js/export.js.php +++ b/web/skins/classic/views/js/export.js.php @@ -14,6 +14,6 @@ var eidParm = 'eid='; ?> var exportReady = ; -var exportFile = ''; +var exportFile = '?view=archive&type='; var exportProgressString = ''; From 98e0a0d2c56a06d3d82ca9cf4578865a821d9baf Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:16:37 -0800 Subject: [PATCH 18/92] Don't output Fatal(...) error messages unless debugging is on to avoid leaking info. Fixes #2459 --- web/includes/logger.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/includes/logger.php b/web/includes/logger.php index 8bc81fb97..b3048bc1a 100644 --- a/web/includes/logger.php +++ b/web/includes/logger.php @@ -455,7 +455,10 @@ function Error( $string ) { function Fatal( $string ) { Logger::fetch()->logPrint( Logger::FATAL, $string ); - die( htmlentities($string) ); + if (Logger::fetch()->debugOn()) { + echo(htmlentities($string)); + } + exit(1); } function Panic( $string ) { From fa6716a64b7481677b0d8d73d460200e60429410 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 02:28:40 -0800 Subject: [PATCH 19/92] console: Escape source column output to prevent XSS. Fixes #2452 --- web/skins/classic/views/console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index aa909700e..6270b60ac 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -308,7 +308,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { Name(); ?> '. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.$Monitor->Source().'', canEdit('Monitors') ).''; + echo ''. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.validHtmlStr($Monitor->Source()).'', canEdit('Monitors') ).''; if ( $show_storage_areas ) { ?> Name(); } ?> From 7b0ee8a6a22576b66c341ee6f09668852769cbb6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 14:05:50 -0800 Subject: [PATCH 20/92] group: Escape group name in heading. Fixes #2454 --- web/skins/classic/views/group.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index 9ccbd112c..eafb4683c 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -34,7 +34,7 @@ xhtmlHeaders(__FILE__, translate('Group').' - '.$newGroup->Name());
From c8066919ff159a121436862781eb7d1aaa81fb01 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 14:14:46 -0800 Subject: [PATCH 21/92] functions.php: Esacepe textContent in htmlOptions() --- web/includes/functions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 4aea38a60..a3723c635 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -496,7 +496,6 @@ function makePopupButton( $url, $winName, $winSize, $buttonValue, $condition=1, } function htmlSelect( $name, $contents, $values, $behaviours=false ) { - $behaviourText = ''; if ( !empty($behaviours) ) { if ( is_array($behaviours) ) { @@ -537,7 +536,7 @@ function htmlOptions($contents, $values) { $options_html .= ""; + ">".htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).""; } return $options_html; } From b2a97ee190c6dc3e30b9c36b9c33c33348dde4d6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:10:42 -0800 Subject: [PATCH 22/92] frame.php: Fix multiple XSS from 'show' and 'scale' parameters and enforce CSP. Fixes #2448, fixes #2449, and fixes #2447. --- web/includes/functions.php | 1 + web/skins/classic/css/base/views/frame.css | 5 ---- web/skins/classic/css/classic/views/frame.css | 5 ---- web/skins/classic/css/dark/views/frame.css | 5 ---- web/skins/classic/views/frame.php | 23 ++++++++++--------- web/skins/classic/views/js/frame.js | 8 ++++++- web/skins/classic/views/js/frame.js.php | 2 +- 7 files changed, 21 insertions(+), 28 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index a3723c635..85e3b022c 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -56,6 +56,7 @@ function CSPHeaders($view, $nonce) { case 'download': case 'error': case 'export': + case 'frame': case 'function': case 'log': case 'logout': diff --git a/web/skins/classic/css/base/views/frame.css b/web/skins/classic/css/base/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/base/views/frame.css +++ b/web/skins/classic/css/base/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/css/classic/views/frame.css b/web/skins/classic/css/classic/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/classic/views/frame.css +++ b/web/skins/classic/css/classic/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/css/dark/views/frame.css b/web/skins/classic/css/dark/views/frame.css index c9cb1846c..947fee1bc 100644 --- a/web/skins/classic/css/dark/views/frame.css +++ b/web/skins/classic/css/dark/views/frame.css @@ -9,8 +9,3 @@ display: flex; justify-content: space-between; } - -#controls a { - width: 40px; - margin-left: -20px; -} diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index 931951056..ae69fecba 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -51,14 +51,15 @@ $lastFid = $maxFid; $alarmFrame = $Frame->Type()=='Alarm'; if ( isset( $_REQUEST['scale'] ) ) { - $scale = $_REQUEST['scale']; + $scale = validNum($_REQUEST['scale']); } else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) { - $scale = $_COOKIE['zmWatchScale'.$Monitor->Id()]; + $scale = validNum($_COOKIE['zmWatchScale'.$Monitor->Id()]); } else if ( isset( $_COOKIE['zmWatchScale'] ) ) { - $scale = $_COOKIE['zmWatchScale']; + $scale = validNum($_COOKIE['zmWatchScale']); } else { $scale = max( reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); } +$scale = $scale ?: "auto"; $imageData = $Event->getImageSrc( $frame, $scale, 0 ); if ( ! $imageData ) { @@ -67,7 +68,7 @@ if ( ! $imageData ) { } $show = 'capt'; -if ( isset($_REQUEST['show']) ) { +if (isset($_REQUEST['show']) && in_array($_REQUEST['show'], array('capt', 'anal'))) { $show = $_REQUEST['show']; } else if ( $imageData['hasAnalImage'] ) { $show = 'anal'; @@ -89,9 +90,9 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id()." - ".$Frame->Frame
Id().'&fid='.$Frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?> - +
-
+

Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?>

@@ -103,19 +104,19 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id()." - ".$Frame->Frame ', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) ); } ?> -<?php echo $Frame->EventId().FrameId() ?>" class=""/> +<?php echo $Frame->EventId().FrameId() ?>" class=""/>

FrameId() > 1 ) { ?> - - + + FrameId() < $maxFid ) { ?> - - + +

diff --git a/web/skins/classic/views/js/frame.js b/web/skins/classic/views/js/frame.js index e0401c7c7..03058ff8a 100644 --- a/web/skins/classic/views/js/frame.js +++ b/web/skins/classic/views/js/frame.js @@ -30,4 +30,10 @@ function changeScale() { }); } -if (scale == 'auto') $j(document).ready(changeScale); +if (scale == 'auto') { + $j(document).ready(changeScale); +} + +document.addEventListener('DOMContentLoaded', function onDCL() { + document.getElementById('scale').addEventListener('change', changeScale); +}); diff --git a/web/skins/classic/views/js/frame.js.php b/web/skins/classic/views/js/frame.js.php index c9b3f2eea..572587f82 100644 --- a/web/skins/classic/views/js/frame.js.php +++ b/web/skins/classic/views/js/frame.js.php @@ -1,3 +1,3 @@ -var scale = ''; +var scale = ''; var SCALE_BASE = ; From 70e59ed546474bf18b9af2040d0ed732dce835bc Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:19:15 -0800 Subject: [PATCH 23/92] filter.php: Escape the filter name on output. Fixes #2455 --- web/skins/classic/views/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index fab68941c..b74c4fd58 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -188,7 +188,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )

- +

From dd37808ef790a77100845c2c3c3bb28d9038950f Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:24:13 -0800 Subject: [PATCH 24/92] filter.php: Escape AutoExecuteCmd before output to prevent XSS. Fixes #2461 --- web/skins/classic/views/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index b74c4fd58..53b7f588c 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -385,7 +385,7 @@ if ( ZM_OPT_MESSAGE ) {

AutoExecute() ) { ?> checked="checked"/> - +

From bb75dad091bfa35af49467fede06adb972ed0545 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 15:35:55 -0800 Subject: [PATCH 25/92] filter.php: Escape filter query term value to avoid XSS. Fixes #2462 --- web/skins/classic/views/filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 53b7f588c..cba9ad3e3 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -281,13 +281,13 @@ for ( $i=0; $i < count($terms); $i++ ) { } else { ?>

- + - + From 254b7286b4d2654b95080a175c44195667e42ea8 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 16:41:54 -0800 Subject: [PATCH 26/92] monitor.php: Escape SignalCheckColour to prevent XSS. Fixes #2451 --- web/includes/Monitor.php | 14 ++++++++++++++ web/skins/classic/views/monitor.php | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index cc1d8eed7..538793ffb 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -331,6 +331,20 @@ private $control_fields = array( return $this->defaults{$field}; } // end function Height + 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. + if (array_key_exists($field, $this) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) { + return $this->{$field}; + } + return $this->defaults{$field}; + } // end function SignalCheckColour + public function set($data) { foreach ($data as $k => $v) { if ( method_exists($this, $k) ) { diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 59e4ca04f..df78bbda9 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -1021,7 +1021,7 @@ if ( $monitor->Type() == 'Local' ) { From cef54feaf9bf1374f0404bf525cdd322300882b5 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 16:54:06 -0800 Subject: [PATCH 27/92] monitor.php: Escape a bug of output variables. Fixes #2465 --- web/skins/classic/views/monitor.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index df78bbda9..254adcdfa 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -462,7 +462,7 @@ if ( canEdit( 'Monitors' ) ) { if ( isset ($_REQUEST['dupId'])) { ?>
- Configuration cloned from Monitor: + Configuration cloned from Monitor:
Id() || ($monitor->Id()!= $linked_monitor['Id'])) && visibleMonitor( $linked_monitor['Id'] ) ) { ?> - + GroupIds() ); V4LMultiBuffer() ? 'checked="checked"' : '' ) ?>/>
- + Type() == 'NVSocket' ) { @@ -873,7 +873,7 @@ include('_monitor_source_nvsocket.php'); - + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> @@ -897,11 +897,11 @@ if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) { } if ( $monitor->Type() == 'Local' ) { ?> - + Type() != 'WebSite' ) { ?> - + @@ -915,7 +915,7 @@ if ( $monitor->Type() == 'Local' ) { } case 'storage' : ?> - + - + Date: Sat, 9 Feb 2019 17:01:45 -0800 Subject: [PATCH 28/92] monitor.php: Escape monitor method. Fixes #2464 --- web/skins/classic/views/monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 254adcdfa..0b8d78a8e 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -523,7 +523,7 @@ foreach ( $tabs as $name=>$value ) { - + From ef0e5f453a4e60a5bdd6bc347e517a87182b6cad Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:11:53 -0800 Subject: [PATCH 29/92] monitor.php: Fix XSS from LinkedMonitors. Fixes #2463 --- web/skins/classic/views/monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 0b8d78a8e..7a5665631 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -522,7 +522,7 @@ foreach ( $tabs as $name=>$value ) { - + Date: Sat, 9 Feb 2019 17:15:02 -0800 Subject: [PATCH 30/92] functions.php: Fix SQLi in getFormChanges --- 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 85e3b022c..fab696ae7 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -612,7 +612,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { { if ( is_array($newValues[$key]) ) { if ( (!isset($values[$key])) or ( join(',',$newValues[$key]) != $values[$key] ) ) { - $changes[$key] = "`$key` = ".dbEscape(join(',',$newValues[$key])); + $changes[$key] = "`$key` = '".dbEscape(join(',',$newValues[$key]))."'"; } } else if ( (!isset($values[$key])) or $values[$key] ) { $changes[$key] = "`$key` = ''"; From fcbc22b6a27b2375327327c3d75995fe6a3cafd9 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:27:47 -0800 Subject: [PATCH 31/92] functions.php: Ensure 'limit' request parameter is an integer. Fixes #2456 --- web/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index fab696ae7..e4da8d150 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1085,7 +1085,7 @@ function parseSort( $saveToSession=false, $querySep='&' ) { $_SESSION['sort_asc'] = validHtmlStr($_REQUEST['sort_asc']); } if ($_REQUEST['limit'] != '') { - $limitQuery = "&limit=".$_REQUEST['limit']; + $limitQuery = "&limit=".validInt($_REQUEST['limit']); } } @@ -1426,7 +1426,7 @@ function getPagination( $pages, $page, $maxShortcuts, $query, $querySep='&' function sortHeader( $field, $querySep='&' ) { global $view; - return( '?view='.$view.$querySep.'page=1'.$_REQUEST['filter']['query'].$querySep.'sort_field='.$field.$querySep.'sort_asc='.($_REQUEST['sort_field'] == $field?!$_REQUEST['sort_asc']:0).$querySep.'limit='.$_REQUEST['limit'] ); + return '?view='.$view.$querySep.'page=1'.$_REQUEST['filter']['query'].$querySep.'sort_field='.$field.$querySep.'sort_asc='.($_REQUEST['sort_field'] == $field?!$_REQUEST['sort_asc']:0).$querySep.'limit='.validInt($_REQUEST['limit']); } function sortTag( $field ) { From 6d2f3c265f6154181a4452bdefdd990b4f0b22b6 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:34:59 -0800 Subject: [PATCH 32/92] events.php: Remove inline event handlers and enforce CSP --- web/includes/functions.php | 1 + web/skins/classic/views/events.php | 4 ++-- web/skins/classic/views/js/events.js | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e4da8d150..891e986ff 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -55,6 +55,7 @@ function CSPHeaders($view, $nonce) { case 'donate': case 'download': case 'error': + case 'events': case 'export': case 'frame': case 'function': diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 3beff0188..0526dc8c2 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -100,7 +100,7 @@ xhtmlHeaders(__FILE__, translate('Events') ); diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index b594faa20..831490f78 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -169,6 +169,14 @@ function initPage() { $j('input[name=markEids\\[\\]]').each(function() { this.addEventListener('click', configureButton, false); }); + document.getElementById("refreshLink").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + document.getElementById("backLink").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); } $j(document).ready(initPage); From 9ce05a9a09de47868398a09e6c5259645b9ee73e Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 17:45:52 -0800 Subject: [PATCH 33/92] user.php: Escape the Username upon display. Fixes #2467 --- web/skins/classic/views/user.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/skins/classic/views/user.php b/web/skins/classic/views/user.php index 95ed639a5..b85d73483 100644 --- a/web/skins/classic/views/user.php +++ b/web/skins/classic/views/user.php @@ -58,14 +58,14 @@ xhtmlHeaders(__FILE__, translate('User').' - '.$newUser['Username']);
- +
-      +     
()
()
Type() == 'Local' ) {
- + - + - + From 6af2c4ad0e288fae5702e96391657d173bba2297 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 18:06:21 -0800 Subject: [PATCH 34/92] Escape output of WEB_TITLE, HOME_URL, HOME_CONTENT, & WEB_CONSOLE_BANNER. Fixes #2468 --- web/skins/classic/includes/functions.php | 8 ++++---- web/skins/classic/views/login.php | 2 +- web/skins/classic/views/logout.php | 2 +- web/skins/classic/views/none.php | 2 +- web/skins/classic/views/postlogin.php | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 703cd49d3..063977942 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -57,7 +57,7 @@ function xhtmlHeaders( $file, $title ) { - <?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?> + <?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> - <?php echo validHtmlStr($title) ?> @@ -254,7 +254,7 @@ function getNavBarHTML($reload = null) { - + -

account_circle

+

account_circle

diff --git a/web/skins/classic/views/logout.php b/web/skins/classic/views/logout.php index 772bacd80..1b38d812f 100644 --- a/web/skins/classic/views/logout.php +++ b/web/skins/classic/views/logout.php @@ -25,7 +25,7 @@ xhtmlHeaders(__FILE__, translate('Logout') );
diff --git a/web/skins/classic/views/none.php b/web/skins/classic/views/none.php index da04ed19b..1213b44d5 100644 --- a/web/skins/classic/views/none.php +++ b/web/skins/classic/views/none.php @@ -25,7 +25,7 @@ $skinJsFile = getSkinFile('js/skin.js'); - <?php echo ZM_WEB_TITLE_PREFIX ?> + <?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> "; + echo ""; } # end if tab == skins ?> @@ -95,7 +99,7 @@ foreach ( $tabs as $name=>$value ) { - +
@@ -132,7 +136,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI - + @@ -199,7 +203,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI -
+ @@ -264,7 +268,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI -
+ @@ -328,7 +332,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI $configCats[$tab]['ZM_BANDWIDTH_DEFAULT']['Hint'] = $bandwidth_options; } ?> - + diff --git a/web/skins/classic/views/plugin.php b/web/skins/classic/views/plugin.php index 4f3b4ccf2..ea7a9f347 100644 --- a/web/skins/classic/views/plugin.php +++ b/web/skins/classic/views/plugin.php @@ -107,7 +107,7 @@ function pLang($name)

- -

- + diff --git a/web/skins/classic/views/privacy.php b/web/skins/classic/views/privacy.php index 9bd283b4a..21c0bdb59 100644 --- a/web/skins/classic/views/privacy.php +++ b/web/skins/classic/views/privacy.php @@ -40,7 +40,7 @@ xhtmlHeaders(__FILE__, translate('Privacy') );

ZoneMinder -

- +
diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 5a3b5e5b6..70808138e 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -113,7 +113,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { ?> - + @@ -205,7 +205,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $Group = new Group($group_id); $Groups = $Group->Parents(); array_push($Groups, $Group); - return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); + return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); }, $Monitor->GroupIds() ) ); ?>
diff --git a/web/skins/classic/views/server.php b/web/skins/classic/views/server.php index 64508995d..0c028b8c1 100644 --- a/web/skins/classic/views/server.php +++ b/web/skins/classic/views/server.php @@ -39,7 +39,7 @@ xhtmlHeaders(__FILE__, translate('Server').' - '.$Server->Name());

Name() ?>

- + diff --git a/web/skins/classic/views/settings.php b/web/skins/classic/views/settings.php index 2ed9e7c5d..1946642b6 100644 --- a/web/skins/classic/views/settings.php +++ b/web/skins/classic/views/settings.php @@ -44,7 +44,7 @@ xhtmlHeaders(__FILE__, validHtmlStr($monitor['Name'])." - ".translate('Settings'

-

- + diff --git a/web/skins/classic/views/state.php b/web/skins/classic/views/state.php index cb8e5403a..dead5ebf5 100644 --- a/web/skins/classic/views/state.php +++ b/web/skins/classic/views/state.php @@ -24,7 +24,7 @@ if ( !canEdit('System') ) { } ?>
diff --git a/web/skins/classic/views/storage.php b/web/skins/classic/views/storage.php index 7ec3a63cf..8da0ba5b5 100644 --- a/web/skins/classic/views/storage.php +++ b/web/skins/classic/views/storage.php @@ -63,7 +63,7 @@ xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );

- + diff --git a/web/skins/classic/views/user.php b/web/skins/classic/views/user.php index b85d73483..931e58321 100644 --- a/web/skins/classic/views/user.php +++ b/web/skins/classic/views/user.php @@ -61,7 +61,7 @@ xhtmlHeaders(__FILE__, translate('User').' - '.$newUser['Username']);

- + diff --git a/web/skins/classic/views/version.php b/web/skins/classic/views/version.php index a7562f355..3ced8c613 100644 --- a/web/skins/classic/views/version.php +++ b/web/skins/classic/views/version.php @@ -63,7 +63,7 @@ if ( ZM_DYN_DB_VERSION && (ZM_DYN_DB_VERSION != ZM_VERSION) ) { - +

diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index 85a8abb6c..aab9278d6 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -123,7 +123,7 @@ if ( isset($_REQUEST['showIndex']) ) { - +
diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index 4a172083f..66f379e90 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -122,7 +122,7 @@ xhtmlHeaders(__FILE__, translate('Zone') );

Name() ?> -

- + diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index c66ffd000..7a176acc7 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -52,7 +52,7 @@ xhtmlHeaders(__FILE__, translate('Zones') );

- + From a97711de89d808edcec1b422b5c97645dbd9f501 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:12:36 -0800 Subject: [PATCH 40/92] Replace or sanitize remaining uses of PHP_SELF. Fixes #2446 --- web/includes/Frame.php | 5 ++--- web/includes/Server.php | 3 ++- web/includes/actions/groups.php | 2 +- web/includes/actions/login.php | 2 +- web/includes/actions/montage.php | 2 +- web/includes/actions/options.php | 2 +- web/includes/actions/privacy.php | 4 ++-- web/includes/functions.php | 4 ++-- web/skins/classic/js/skin.js.php | 6 +++++- 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/web/includes/Frame.php b/web/includes/Frame.php index 74a18ef59..d4c2a4dee 100644 --- a/web/includes/Frame.php +++ b/web/includes/Frame.php @@ -50,9 +50,8 @@ class Frame { } public function getImageSrc( $show='capture' ) { - - return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'FrameId'}.'&eid='.$this->{'EventId'}.'&show='.$show; - #return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg'; + return '?view=image&fid='.$this->{'FrameId'}.'&eid='.$this->{'EventId'}.'&show='.$show; + #return '?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg'; } // end function getImageSrc public static function find( $parameters = array(), $options = NULL ) { diff --git a/web/includes/Server.php b/web/includes/Server.php index 65721214d..ea633c4be 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -117,7 +117,8 @@ class Server { if ( isset($this->{'PathToIndex'}) and $this->{'PathToIndex'} ) { return $this->{'PathToIndex'}; } - return $_SERVER['PHP_SELF']; + // We can't trust PHP_SELF to not include an XSS vector. See note in skin.js.php. + return preg_replace('/\.php.*$/i', '.php', $_SERVER['PHP_SELF']); } public function UrlToIndex( $port=null ) { diff --git a/web/includes/actions/groups.php b/web/includes/actions/groups.php index 200f65f99..22d138240 100644 --- a/web/includes/actions/groups.php +++ b/web/includes/actions/groups.php @@ -43,7 +43,7 @@ if ( $action == 'delete' ) { $Group->delete(); } } - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=groups'; + $redirect = '?view=groups'; $refreshParent = true; } # end if action ?> diff --git a/web/includes/actions/login.php b/web/includes/actions/login.php index b497b29f5..5e35987c8 100644 --- a/web/includes/actions/login.php +++ b/web/includes/actions/login.php @@ -29,7 +29,7 @@ if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 're $view = 'login'; } else { $view = 'postlogin'; - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; } } ?> diff --git a/web/includes/actions/montage.php b/web/includes/actions/montage.php index 7182ba2dc..3040fd83a 100644 --- a/web/includes/actions/montage.php +++ b/web/includes/actions/montage.php @@ -40,7 +40,7 @@ if ( isset($_REQUEST['object']) ) { $_SESSION['zmMontageLayout'] = $Layout->Id(); setcookie('zmMontageLayout', $Layout->Id(), 1); session_write_close(); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=montage'; + $redirect = '?view=montage'; } // end if save } # end if isset($_REQUEST['object'] ) diff --git a/web/includes/actions/options.php b/web/includes/actions/options.php index 263a592f8..d7853ec9e 100644 --- a/web/includes/actions/options.php +++ b/web/includes/actions/options.php @@ -89,7 +89,7 @@ if ( $action == 'delete' ) { case 'lowband' : break; } - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=options&tab='.$_REQUEST['tab']; + $redirect = '?view=options&tab='.$_REQUEST['tab']; } loadConfig(false); return; diff --git a/web/includes/actions/privacy.php b/web/includes/actions/privacy.php index 19c4061ea..99bbd7150 100644 --- a/web/includes/actions/privacy.php +++ b/web/includes/actions/privacy.php @@ -28,12 +28,12 @@ if ( ($action == 'privacy') && isset($_REQUEST['option']) ) { case 'decline' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_TELEMETRY_DATA'"); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; break; case 'accept' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '1' WHERE Name = 'ZM_TELEMETRY_DATA'"); - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + $redirect = '?view=console'; break; default: # Enable the privacy statement if we somehow submit something other than accept or decline dbQuery("UPDATE Config SET Value = '1' WHERE Name = 'ZM_SHOW_PRIVACY'"); diff --git a/web/includes/functions.php b/web/includes/functions.php index cbb54f1c9..f0e087d48 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -294,7 +294,7 @@ function getImageStreamHTML( $id, $src, $width, $height, $title='' ) { function outputControlStream( $src, $width, $height, $monitor, $scale, $target ) { ?> - + @@ -364,7 +364,7 @@ function getWebSiteUrl( $id, $src, $width, $height, $title='' ) { function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) { ?> - + diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index 1d0cfd61c..a9f6b85af 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -29,7 +29,11 @@ var AJAX_TIMEOUT = ; var navBarRefresh = ; var currentView = ''; -var thisUrl = ''; + +var thisUrl = ''; var skinPath = ''; var serverId = ''; From dbc1c7b72f8cab5094a4a498a66ca2c0d3f29872 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:39:54 -0800 Subject: [PATCH 41/92] Only output the CSRF Try Again button (and add a warning) when ZM_LOG_DEBUG is on. Fixes #2469 --- web/includes/csrf/csrf-magic.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php index 692015e70..576a8ef2a 100644 --- a/web/includes/csrf/csrf-magic.php +++ b/web/includes/csrf/csrf-magic.php @@ -288,9 +288,13 @@ function csrf_callback($tokens) { echo "CSRF check failed

CSRF check failed. Your form session may have expired, or you may not have - cookies enabled.

- $data -

Debug: $tokens

+ cookies enabled.

"; + if (ZM_LOG_DEBUG) { + // Don't make it too easy for users to inflict a CSRF attach on themselves. + echo "

Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.

"; + echo "
$data"; + } + echo "

Debug: $tokens

"; } From a6ee79f428ee8b99b23906a563256050a41e3663 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sat, 9 Feb 2019 22:40:39 -0800 Subject: [PATCH 42/92] Fix typo in dbc1c7b72f8cab5094a4a498a66ca2c0d3f29872 comment --- web/includes/csrf/csrf-magic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php index 576a8ef2a..584432ef7 100644 --- a/web/includes/csrf/csrf-magic.php +++ b/web/includes/csrf/csrf-magic.php @@ -290,7 +290,7 @@ function csrf_callback($tokens) {

CSRF check failed. Your form session may have expired, or you may not have cookies enabled.

"; if (ZM_LOG_DEBUG) { - // Don't make it too easy for users to inflict a CSRF attach on themselves. + // Don't make it too easy for users to inflict a CSRF attack on themselves. echo "

Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.

"; echo "
$data"; } From c8e41bfee75cb0a70e69d8f1488aa948fc31831a Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 00:10:39 -0800 Subject: [PATCH 43/92] log.php: Ensure 'line' is an integer. Helps with #2466 --- web/ajax/log.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index 282303a87..2a5aa039e 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -15,7 +15,7 @@ switch ( $_REQUEST['task'] ) { $file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/[\w.:]+\//', '', $_POST['file'] ) : ''; if ( !empty( $_POST['line'] ) ) - $line = $_POST['line']; + $line = validInt($_POST['line']); else $line = NULL; From c9032d3cb41d3aef0fd21dc0bd47302816788c66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Feb 2019 11:53:57 -0500 Subject: [PATCH 44/92] add autocomplete tags to username and password inputs --- web/skins/classic/views/login.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/login.php b/web/skins/classic/views/login.php index 75e8479c3..c75c9b602 100644 --- a/web/skins/classic/views/login.php +++ b/web/skins/classic/views/login.php @@ -19,10 +19,10 @@ xhtmlHeaders(__FILE__, translate('Login') );

account_circle

- + - + Date: Mon, 11 Feb 2019 05:08:58 +1100 Subject: [PATCH 45/92] Set CSRF on as the default for new installs. Fixes #2507 (#2508) * Set CSRF on as the default for new installs. Not sure we can impact config on existing installations. * Fix the spelling mistake that I noticed after editing this. --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index ff5b6ea33..536389062 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -366,7 +366,7 @@ our @options = ( }, { name => 'ZM_ENABLE_CSRF_MAGIC', - default => 'no', + default => 'yes', description => 'Enable csrf-magic library', help => q` CSRF stands for Cross-Site Request Forgery which, under specific @@ -375,11 +375,7 @@ our @options = ( this, the attacker must write a very specific web page and get you to navigate to it, while you are logged into the ZoneMinder web console at the same time. Enabling ZM_ENABLE_CSRF_MAGIC will - help mitigate these kinds of attackes. Be warned this feature - is experimental and may cause problems, particularly with the API. - If you find a false positive and can document how to reproduce it, - then please report it. This feature defaults to OFF currently due to - its experimental nature. + help mitigate these kinds of attacks. `, type => $types{boolean}, category => 'system', From 2975225918947afa830feefb8f7b27dccfbe76ea Mon Sep 17 00:00:00 2001 From: Steve Gilvarry Date: Mon, 11 Feb 2019 05:09:40 +1100 Subject: [PATCH 46/92] Cleanup old files (#2509) * Remove Doc-Pak folder Duplicates and out of date * Delete umutils dir, looks like some old build script. * Remove NEWS file as it is not being used. * Remove TODO * Remove description-pak, hanging around since NextTime days * Delete ChangeLog file leaving CHANGELOG.MD as main file, which needs updating.. * Remove INSTALL file as it was not up to date, happy to consider an update instead. * Remove Authors, not really adding much value and pretty sure the history is documented elsewhere. * Deleted BUGS. Should be covered in the readme, let me know if you want me to add a link.. --- AUTHORS | 10 -- BUGS | 1 - ChangeLog | 1 - INSTALL | 147 ---------------- NEWS | 1 - TODO | 2 - description-pak | 1 - doc-pak/AUTHORS | 6 - doc-pak/BUGS | 1 - doc-pak/COPYING | 340 ------------------------------------ doc-pak/ChangeLog | 1 - doc-pak/INSTALL | 185 -------------------- doc-pak/NEWS | 1 - doc-pak/README | 5 - doc-pak/TODO | 2 - umutils/nextimeconfigure.zm | 16 -- 16 files changed, 720 deletions(-) delete mode 100644 AUTHORS delete mode 100644 BUGS delete mode 100644 ChangeLog delete mode 100644 INSTALL delete mode 100644 NEWS delete mode 100644 TODO delete mode 100644 description-pak delete mode 100644 doc-pak/AUTHORS delete mode 100644 doc-pak/BUGS delete mode 100644 doc-pak/COPYING delete mode 100644 doc-pak/ChangeLog delete mode 100644 doc-pak/INSTALL delete mode 100644 doc-pak/NEWS delete mode 100644 doc-pak/README delete mode 100644 doc-pak/TODO delete mode 100755 umutils/nextimeconfigure.zm diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 72d39764f..000000000 --- a/AUTHORS +++ /dev/null @@ -1,10 +0,0 @@ -ZoneMinder - A Linux based camera monitoring and analysis tool. - -This project was imagined and created by Philip Coombes in -September 2002, shortly after being burglarised of his power tools. -He can be contacted at philip.coombes@zoneminder.com - -In early 2013 after nearly two years of no development, -the community reached out to Phil in an attempt to open up the -project. With Phil's blessing, the code was migrated to github, -and the community took over the project. diff --git a/BUGS b/BUGS deleted file mode 100644 index b78c01bed..000000000 --- a/BUGS +++ /dev/null @@ -1 +0,0 @@ -Please see https://github.com/ZoneMinder/ZoneMinder/issues?state=open diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index afab3413a..000000000 --- a/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -This is too hard to maintain. See https://github.com/ZoneMinder/ZoneMinder/commits/master diff --git a/INSTALL b/INSTALL deleted file mode 100644 index ecf7b909a..000000000 --- a/INSTALL +++ /dev/null @@ -1,147 +0,0 @@ -Installing ZoneMinder with cmake --------------------------------- -Starting with ZoneMinder 1.26.4, ZoneMinder can now be installed using cmake. This requires cmake version 2.6 or newer. -cmake is an alternative to the autotools collection (libtool, autoconf, automake, autoheader and such). Its more recent and has many advantages, including, but not limited to: -* One program (cmake) instead of multiple. (libtool, autoconf, automake, etc) -* One file per directory (CMakeLists.txt) instead of multiple. (configure.ac, Makefile.am and sometimes more) -* One syntax (cmake's syntax) instead of multiple. (bash and m4) -* Generation of makefiles for many platforms, including Windows. -* Newer than autotools and is being actively developed. -* Generates colored makefiles with progress indicator. -* Slightly faster because its based on C and not bash. -* Lots of documentation, unlike autotools: http://www.cmake.org/cmake/help/cmake2.6docs.html - -At this point, its still possible to use autotools for the ZoneMinder project. Choosing cmake or autotools is now a matter of preference. -Hopefully in the future, cmake will become the default way to install ZoneMinder. - -Important differences ---------------------- -* Unlike the autotools way, the cmake way does not require any options. It attempts to detect some things by its own (system directories, libarch, web user and group) and uses defaults for others (installation paths and such). -* Unlike the autotools way, which links the binaries to a fixed list of libraries, the cmake way only links to libraries that it found on the system. If a library is not found, but required, a fatal error will be shown during the configuration step. -* Unlike the autotools way, the cmake way does not modify the system in any way it shouldn't. It only does what its supposed to do: Install files to your system. Nothing else and nothing leaks out of the DESTDIR environment variable (if used). This means that depending on your configuration, there might be an extra required step after installation: to link WEB_PATH/events and WEB_PATH/images folders to the correct places. - -Configuration -------------- -cmake by default does not require any parameters, but its possible to override the defaults with the options below. - -Configuration can be done in 4 ways: -1) As a command line parameter, e.g. cmake -DCMAKE_VERBOSE_MAKEFILE=ON . -2) Using cmake-gui -3) Providing cmake with an initial cache file with the -C option - IMPORTANT: Do not use the -C option if any major part of your system, excluding the version of zoneminder, has changed. - For example, do not use this option if: you have upgraded your distro to a new version, have gone from 32 to 64 bits, - or have migrated from one machine to another. -4) By editing the cache file CMakeCache.txt (after it has been generated) - Not recommended - -Possible configuration options: - ZM_RUNDIR Location of transient process files, default: /var/run/zm - ZM_SOCKDIR Location of Unix domain socket files, default /var/run/zm - ZM_TMPDIR Location of temporary files, default: /tmp/zm - ZM_LOGDIR Location of generated log files, default: /var/log/zm - ZM_WEBDIR Location of the web files, default: /share/zoneminder/www - ZM_CGIDIR Location of the cgi-bin files, default: /libexec/zoneminder/cgi-bin - ZM_CONTENTDIR Location of dynamic content (events and images), default: /var/lib/zoneminder - ZM_DB_HOST Hostname where ZoneMinder database located, default: localhost - ZM_DB_NAME Name of ZoneMinder database, default: zm - ZM_DB_USER Name of ZoneMinder database user, default: zmuser - ZM_DB_PASS Password of ZoneMinder database user, default: zmpass - ZM_DB_SSL_CA_CERT Path to SSL CA certificate, default: empty; SSL not enabled - ZM_DB_SSL_CLIENT_KEY Path to SSL client key, default: empty; SSL not enabled - ZM_DB_SSL_CLIENT_CERT Path to SSL client certificate, default: empty; SSL not enabled - ZM_WEB_USER The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force - ZM_WEB_GROUP The group apache or the local web server runs on, Leave empty to be the same as the web user - ZM_DIR_EVENTS Location where events are recorded to, default: ZM_CONTENTDIR/events - ZM_DIR_SOUNDS Location to look for optional sound files, default: sounds - ZM_PATH_ZMS Web url to zms streaming server, default: /cgi-bin/nph-zms -Advanced: - ZM_PATH_MAP Location to save mapped memory files, default: /dev/shm - ZM_PATH_ARP Full path to compatible arp binary. Leave empty for automatic detection. - ZM_CONFIG_DIR Location of the main ZoneMinder config file, zm.conf. default: /etc/zm - ZM_CONFIG_SUBDIR Location of custom config files. default: ZM_CONFIG_DIR/conf.d - ZM_EXTRA_LIBS A list of optional libraries, separated by semicolons, e.g. ssl;theora - ZM_MYSQL_ENGINE MySQL engine to use with database, default: InnoDB - ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF - ZM_NO_X10 Set to ON to build ZoneMinder without X10 support. default: OFF - ZM_PERL_MM_PARMS By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly. default: "INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1" - ZM_PERL_SEARCH_PATH Use to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path. default: "" - -Useful configuration options provided by cmake: -CMAKE_VERBOSE_MAKEFILE - Set this to ON (default OFF) to see what cmake is doing. Very useful for troubleshooting. -CMAKE_BUILD_TYPE - Set this to Debug (default Release) to build ZoneMinder with debugging enabled. -CMAKE_INSTALL_PREFIX - Use this to change the prefix (default /usr/local). This option behaves like --prefix from autoconf. Package maintainers will probably want to set this to "/usr". - -Useful environment variables provided by cmake: -CMAKE_INCLUDE_PATH - Use this to add to the include search path. -CMAKE_LIBRARY_PATH - Use this to add to the library search path. -CMAKE_PREFIX_PATH - Use this to add to both include and library search paths. /include will be added to the include search path and /lib to the library search path. Multiple paths can be specified, separated by a : character. For example: export CMAKE_PREFIX_PATH="/opt/libjpeg-turbo:/opt/ffmpeg-from-git" - -CFLAGS, CPPFLAGS and other environment variables: -To append to the CFLAGS and CXXFLAGS, please use the CFLAGS and CXXFLAGS environment variables. -Or use the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS configuration options. -To replace the CFLAGS and CXXFLAGS entirely: -* For the Release build type: use CMAKE_C_FLAGS_RELEASE for the CFLAGS and CMAKE_CXX_FLAGS_RELEASE for the CXXFLAGS -* For the Debug build type: use CMAKE_C_FLAGS_DEBUG for the CFLAGS and CMAKE_CXX_FLAGS_DEBUG for the CXXFLAGS -Other important environment variables (such as LDFLAGS) are also supported. - -The DESTDIR environment variable is also supported, however it needs to be set before invoking make install. For example: DESTDIR=mydestdir make install -For more information about DESTDIR, see: -* http://www.gnu.org/prep/standards/html_node/DESTDIR.html - -Basic steps for installing ZoneMinder on a fresh system -------------------------------------------------------- -1) After installing all the required dependencies, in the project directory, run "cmake [extra options] ." -This behaves like ./configure. It is also possible to supply configuration options, e.g. cmake -DZM_DB_PASS="mypass" . -IMPORTANT: Don't forget the dot "." at the end. -2) Run "make" to compile ZoneMinder -3) Run "make install" (as root, or use sudo) to install ZoneMinder to your system. -4) Create a directory for the content and the necessary symlinks by running zmlinkcontent.sh with the directory you want to use. e.g. ./zmlinkcontent.sh /nfs/zm -5) Create a database for zoneminder, called "zm". -6) Create a user for the zoneminder database, called zmuser with password and full privileges to the "zm" database. -NOTE: The database server, database name, user and password can be different and adjusted during configuration step with the options in this file, or by editing /etc/zm.conf -7) Populate the zoneminder database using the script zm_create.sql. This should be found in /share/zoneminder/db or in the project/db directory. - -8) Create an apache virtual host for ZoneMinder. Make sure to use the same paths as ZM_WEBDIR and ZM_CGIDIR in /etc/zm.conf -9) Verify date.timezone is set to your timezone. This parameter is often found inside the system php.ini file. Consult your distribution's documentation for the proper way to set this value. -10) Create other config if desired (e.g. rsyslog, logrotate and such). Some of this can be found in /share/zoneminder/misc or project/misc directory -11) Setup an appropriate startup script for your system. Two generic startup scripts have been provided, a legacy Sys V Init script and a Systemd service file. - -*Sys V Init Setup* -- Copy the sys v init script /scripts/zm from the build folder to /etc/init. -- Inspect the contents to make sure they apply to your distro. - -*SystemD Setup* -- Copy the zoneminder systemd service file /misc/zoneminder.service from the build folder to the systemd service file location. - For Redhat based distros, that folder is /usr/lib/systemd/system. -- Inspect the contents to make sure they apply to your distro. -- Tell systemd to load the new service file: "sudo systemctl daemon-reload". -- Copy /misc/zoneminder-tmpfiles.conf to /etc/tmpfiles.d -- Tell systemd to process this file: "sudo /usr/bin/systemd-tmpfiles --create /etc/tmpfiles.d/zoneminder.conf". - -Basic steps for upgrading ZoneMinder ------------------------------------- -1) If you wish to use the same paths and configuration as the currently installed ZoneMinder, you need to provide cmake with options that match your current installation. -You can provide those options in the command line to cmake, e.g. cmake -DZM_DB_PASS="blah" -DZM_WEBDIR="/usr/local/share/zoneminder/www" -DCMAKE_INSTALL_FULL_BINDIR="/usr/bin" . -Or alternatively, for convenience, use the cmakecacheimport.sh script. This reads a zoneminder configuration file (zm.conf) and creates a cmake initial cache file called zm_conf.cmake, which you can then provide to cmake. -For example: -./cmakecacheimport.sh /etc/zm.conf -cmake -C zm_conf.cmake [extra options] . - -2) Run "make" to compile ZoneMinder -3) Run "make install" (as root, or use sudo) to install ZoneMinder to your system. -4) Depending on your configuration: If DIR_EVENTS is set to default, You will need to update the symlinks in the web directory to the correct folders. e.g. web directory/events should point to the real events directory. -You can use the zmlinkcontent.sh script for this. For example, if /var/lib/zoneminder is the folder that contains the "events" directory, you can use: -./zmlinkcontent.sh /var/lib/zoneminder -By default, the content directory for new installations is /var/lib/zoneminder. This can be overridden in cmake with the ZM_CONTENTDIR option. e.g. cmake -DZM_CONTENTDIR="/some/big/storage/zm" . - -5) Run zmupdate.pl to update the database layout to the new version. - -Uninstallation: ---------------- -By default, cmake does not have an uninstall target, however we have added a one. Simply run make uninstall (or DESTDIR=mydestdir make uninstall if a DESTDIR was used) and it will remove all the files that cmake installed. -It's also possible to do this manually. The file install_manifest.txt contains the list of files installed to the system. This can be used in many ways to delete all files installed by cmake, such as: xargs rm < install_manifest.txt - -Contributions: --------------- -Please visit our GitHub at http://github.com/ZoneMinder/ZoneMinder - - diff --git a/NEWS b/NEWS deleted file mode 100644 index 3160e2dce..000000000 --- a/NEWS +++ /dev/null @@ -1 +0,0 @@ -Please see README file. diff --git a/TODO b/TODO deleted file mode 100644 index f449b2a7e..000000000 --- a/TODO +++ /dev/null @@ -1,2 +0,0 @@ -Please see README.md file. - diff --git a/description-pak b/description-pak deleted file mode 100644 index 7afaa14a4..000000000 --- a/description-pak +++ /dev/null @@ -1 +0,0 @@ -Zoneminder with kfir performances patches and fixes from UnixMedia (nextime) diff --git a/doc-pak/AUTHORS b/doc-pak/AUTHORS deleted file mode 100644 index 7f0362072..000000000 --- a/doc-pak/AUTHORS +++ /dev/null @@ -1,6 +0,0 @@ -ZoneMinder - A Linux based camera monitoring and analysis tool. - -This project was imagined and created by Philip Coombes in -September 2002, shortly after being burglarised of his power tools. - -mailto:philip.coombes@zoneminder.com diff --git a/doc-pak/BUGS b/doc-pak/BUGS deleted file mode 100644 index 3160e2dce..000000000 --- a/doc-pak/BUGS +++ /dev/null @@ -1 +0,0 @@ -Please see README file. diff --git a/doc-pak/COPYING b/doc-pak/COPYING deleted file mode 100644 index d60c31a97..000000000 --- a/doc-pak/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/doc-pak/ChangeLog b/doc-pak/ChangeLog deleted file mode 100644 index 3160e2dce..000000000 --- a/doc-pak/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -Please see README file. diff --git a/doc-pak/INSTALL b/doc-pak/INSTALL deleted file mode 100644 index 1de0ac2ad..000000000 --- a/doc-pak/INSTALL +++ /dev/null @@ -1,185 +0,0 @@ -Basic Installation -================== - - These are generic installation instructions. - - Please see http://www.zoneminder.com/wiki/index.php/Documentation - for full details. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, a file -`config.cache' that saves the results of its tests to speed up -reconfiguring, and a file `config.log' containing compiler output -(useful mainly for debugging `configure'). - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If at some point `config.cache' -contains results you don't want to keep, you may remove or edit it. - - The file `configure.in' is used to create `configure' by a program -called `autoconf'. You only need `configure.in' if you want to change -it or regenerate `configure' using a newer version of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. - - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. You can give `configure' -initial values for variables by setting them in the environment. Using -a Bourne-compatible shell, you can do that on the command line like -this: - CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure - -Or on systems that have the `env' program, you can do it like this: - env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - If you have to use a `make' that does not supports the `VPATH' -variable, you have to compile the package for one architecture at a time -in the source code directory. After you have installed the package for -one architecture, use `make distclean' before reconfiguring for another -architecture. - -Installation Names -================== - - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -PATH as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=PATH' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - -Optional Features -================= - - Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - -Specifying the System Type -========================== - - There may be some features `configure' can not figure out -automatically, but needs to determine by the type of host the package -will run on. Usually `configure' can figure that out, but if it prints -a message saying it can not guess the host type, give it the -`--host=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name with three fields: - CPU-COMPANY-SYSTEM - -See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the host type. - - If you are building compiler tools for cross-compiling, you can also -use the `--target=TYPE' option to select the type of system they will -produce code for and the `--build=TYPE' option to select the type of -system on which you are compiling the package. - -Sharing Defaults -================ - - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Operation Controls -================== - - `configure' recognizes the following options to control how it -operates. - -`--cache-file=FILE' - Use and save the results of the tests in FILE instead of - `./config.cache'. Set FILE to `/dev/null' to disable caching, for - debugging `configure'. - -`--help' - Print a summary of the options to `configure', and exit. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`--version' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`configure' also accepts some other, not widely useful, options. diff --git a/doc-pak/NEWS b/doc-pak/NEWS deleted file mode 100644 index 3160e2dce..000000000 --- a/doc-pak/NEWS +++ /dev/null @@ -1 +0,0 @@ -Please see README file. diff --git a/doc-pak/README b/doc-pak/README deleted file mode 100644 index e3dfa62e1..000000000 --- a/doc-pak/README +++ /dev/null @@ -1,5 +0,0 @@ - -All documentation for ZoneMinder is now online at - -http://www.zoneminder.com/wiki/index.php/Documentation - diff --git a/doc-pak/TODO b/doc-pak/TODO deleted file mode 100644 index 69af9c87e..000000000 --- a/doc-pak/TODO +++ /dev/null @@ -1,2 +0,0 @@ -Please see README file. - diff --git a/umutils/nextimeconfigure.zm b/umutils/nextimeconfigure.zm deleted file mode 100755 index e2c0e2f32..000000000 --- a/umutils/nextimeconfigure.zm +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -#http://tom.webarts.ca/Blog/new-blog-items/buildingzoneminderandrequiredffmpegandx264fromsource - -export LD_LIBRARY_PATH="/usr/local/lib:/opt/libjpeg-turbo/lib:$LD_LIBRARY_PATH" -export LDFLAGS=" -L/home/nextime/zm/libjpeg-turbo-1.2.1/.libs " - - -DEB_HOST_GNU_TYPE=$(dpkg-architecture -qDEB_HOST_GNU_TYPE) -DEB_BUILD_GNU_TYPE=$(dpkg-architecture -qDEB_BUILD_GNU_TYPE) - -CXXFLAGS=" -DZM_FFMPEG_CVS -DHAVE_LIBCRYPTO -msse2 -DJPEG_INCLUDE_DIR=/home/nextime/zm/libjpeg-turbo-1.2.1/ " -CXXFLAGS="$CXXFLAGS -I/home/nextime/zm/libjpeg-turbo-1.2.1/ " - -CXXFLAGS="$CXXFLAGS" ./configure --with-libarch=lib/$DEB_HOST_GNU_TYPE --disable-debug --host=$DEB_HOST_GNU_TYPE --build=$DEB_BUILD_GNU_TYPE --sysconfdir=/etc/zm --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-mysql=/usr --with-webdir=/usr/share/zoneminder --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=no --enable-mmap=yes - From cda4a28feca52b72c72f79605a7e6c3585bc3cc8 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 11:14:55 -0800 Subject: [PATCH 47/92] Fix accidental use of 'let' in 255806bd549392114af4306422cd23445e843259 --- web/skins/classic/views/js/log.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index 293d425b5..218631157 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -67,10 +67,10 @@ function logResponse( respObj ) { // Manually create table cells by setting the text since `push` will set HTML which // can lead to XSS. - let messageCell = new Element('td'); + var messageCell = new Element('td'); messageCell.set('text', log.Message); - let fileCell = new Element('td'); + var fileCell = new Element('td'); fileCell.set('text', log.File); var row = logTable.push( [{content: log.DateTime, properties: {style: 'white-space: nowrap'}}, log.Component, log.Server, log.Pid, log.Code, messageCell, fileCell, log.Line] ); From 28a8af34d5ef097c64a34288029183bae46e358d Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 12:22:44 -0800 Subject: [PATCH 48/92] Request browser name and version for web issues --- .github/ISSUE_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 809393c3e..dbb351b80 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -17,6 +17,7 @@ In order to submit a bug report, please populate the fields below this line. Thi - Version of ZoneMinder [release version, development version, or commit] - How you installed ZoneMinder [e.g. PPA, RPMFusion, from-source, etc] - Full name and version of OS +- Browser name and version (if this is an issue with the web interface) **If the issue concerns a camera** - Make and Model From ef1112801f1f51a840f8b2c429e1b387425f1ef0 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 12:38:18 -0800 Subject: [PATCH 49/92] Request browser name and version for web issues (part 2) --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ce4347efe..b5df0a5ee 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,6 +11,7 @@ assignees: '' - Version of ZoneMinder [release version, development version, or commit] - How you installed ZoneMinder [e.g. PPA, RPMFusion, from-source, etc] - Full name and version of OS +- Browser name and version (if this is an issue with the web interface) **If the issue concerns a camera** - Make and Model From cdbd59f05417a97382e28fb847fead77aa997265 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Sun, 10 Feb 2019 13:10:36 -0800 Subject: [PATCH 50/92] bandwidth.php: Submit to the 'bandwidth' view but render the 'none' view. Fixes #2493 --- web/includes/actions/bandwidth.php | 1 + web/skins/classic/js/skin.js | 2 +- web/skins/classic/views/bandwidth.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/web/includes/actions/bandwidth.php b/web/includes/actions/bandwidth.php index 8a9056cd2..f26cd7206 100644 --- a/web/includes/actions/bandwidth.php +++ b/web/includes/actions/bandwidth.php @@ -23,5 +23,6 @@ if ( $action == 'bandwidth' && isset($_REQUEST['newBandwidth']) ) { $_COOKIE['zmBandwidth'] = validStr($_REQUEST['newBandwidth']); setcookie('zmBandwidth', validStr($_REQUEST['newBandwidth']), time()+3600*24*30*12*10); $refreshParent = true; + $view = 'none'; } ?> diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 3cbb99e49..a14c63bfc 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -155,8 +155,8 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { var tag = el.getAttribute("data-window-tag"); var width = el.getAttribute("data-window-width"); var height = el.getAttribute("data-window-height"); - createPopup(url, name, tag, width, height); evt.preventDefault(); + createPopup(url, name, tag, width, height); }); }); diff --git a/web/skins/classic/views/bandwidth.php b/web/skins/classic/views/bandwidth.php index 196036fb6..e4ca5edd6 100644 --- a/web/skins/classic/views/bandwidth.php +++ b/web/skins/classic/views/bandwidth.php @@ -44,7 +44,7 @@ xhtmlHeaders(__FILE__, translate('Bandwidth') );
- +

From 9675367e03aab9bceb6fc81eed12406dfde56b52 Mon Sep 17 00:00:00 2001 From: Matt N Date: Mon, 11 Feb 2019 06:34:51 -0800 Subject: [PATCH 51/92] event.js: Wait for delete request to succeed before navigating. Fixes #2384 (#2515) --- web/skins/classic/views/js/event.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 952c3d5a7..3f48ebeaa 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -901,8 +901,19 @@ function actQuery( action, parms ) { function deleteEvent() { pauseClicked(); //Provides visual feedback that your click happened. - actQuery( 'delete' ); - streamNext( true ); + + var deleteReq = new Request.JSON({ + url: thisUrl, + method: 'post', + timeout: AJAX_TIMEOUT, + onSuccess: function onDeleteSuccess(respObj, respText) { + getActResponse(respObj, respText); + // We must wait for the deletion to happen before navigating to the next + // event or this request will be cancelled. + streamNext( true ); + }, + }); + deleteReq.send("view=request&request=event&id="+eventData.Id+"&action=delete"); } function renameEvent() { From e79d7ec7363a7db9266f28168f0deca09d35e8f9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 09:55:45 -0500 Subject: [PATCH 52/92] change let to var --- web/skins/classic/views/js/log.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index 293d425b5..218631157 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -67,10 +67,10 @@ function logResponse( respObj ) { // Manually create table cells by setting the text since `push` will set HTML which // can lead to XSS. - let messageCell = new Element('td'); + var messageCell = new Element('td'); messageCell.set('text', log.Message); - let fileCell = new Element('td'); + var fileCell = new Element('td'); fileCell.set('text', log.File); var row = logTable.push( [{content: log.DateTime, properties: {style: 'white-space: nowrap'}}, log.Component, log.Server, log.Pid, log.Code, messageCell, fileCell, log.Line] ); From 5a333e153cf89e35664ed436949fe6e169bb602d Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Mon, 11 Feb 2019 10:58:34 -0500 Subject: [PATCH 53/92] show object detected file, if object detection in place (#2514) --- web/skins/classic/views/events.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 0526dc8c2..38a79223b 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -194,7 +194,23 @@ while ( $event_row = dbFetchNext($results) ) {
+ Notes()) { + # if notes include detection objects, then link it to objdetect.jpg + if (strpos($event->Notes(),"detected:")!== false){ + # make a link + echo makePopupLink( '?view=image&eid='.$event->Id().'&fid=objdetect', 'zmImage', + array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)), + "
".$event->Notes()."
"); + } + elseif ($event->Notes() != 'Forced Web: ') { + echo "
".$event->Notes()."
"; + } + } + ?> + + From 5695be9f32a0ac8f43a4445c4b6274ec6b52cabe Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 13:21:00 -0500 Subject: [PATCH 54/92] rough in a control function in Filter object. Use it to start/stop zmfilter processes when filters are deleted or Saved. --- web/includes/Filter.php | 56 ++++++++++++++++++++++++++++++++- web/includes/actions/filter.php | 31 +++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index ac2ebb61a..67896858e 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -167,7 +167,7 @@ public $defaults = array( } # end find_one() public function delete() { - dbQuery('DELETE FROM Filters WHERE Id = ?', array($this->{'Id'})); + dbQuery('DELETE FROM Filters WHERE Id=?', array($this->{'Id'})); } # end function delete() public function set( $data ) { @@ -186,6 +186,60 @@ public $defaults = array( } } } # end function set + + public function control($command, $server_id=null) { + $Servers = $server_id ? Server::find(array('Id'=>$server_id)) : Server::find(); + if ( !count($Servers) and !$server_id ) { + # This will be the non-multi-server case + $Servers = array(new Server()); + } + foreach ( $Servers as $Server ) { + + if ( !defined('ZM_SERVER_ID') or !$Server->Id() or ZM_SERVER_ID==$Server->Id() ) { + # Local + Logger::Debug("Controlling filter locally $command for server ".$Server->Id()); + daemonControl($command, 'zmfilter.pl', '--filter_id='.$this->{'Id'}); + } else { + # Remote case + + $url = $Server->UrlToIndex(); + if ( ZM_OPT_USE_AUTH ) { + if ( ZM_AUTH_RELAY == 'hashed' ) { + $url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS); + } else if ( ZM_AUTH_RELAY == 'plain' ) { + $url = '?user='.$_SESSION['username']; + $url = '?pass='.$_SESSION['password']; + } else if ( ZM_AUTH_RELAY == 'none' ) { + $url = '?user='.$_SESSION['username']; + } + } + $url .= '&view=filter&action=control&command='.$command.'&Id='.$this->Id().'&ServerId'.$Server->Id(); + Logger::Debug("sending command to $url"); + $data = array(); + if ( defined('ZM_ENABLE_CSRF_MAGIC') ) + $data['__csrf_magic'] = csrf_get_secret(); + + // use key 'http' even if you send the request to https://... + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'content' => http_build_query($data) + ) + ); + $context = stream_context_create($options); + try { + $result = file_get_contents($url, false, $context); + if ( $result === FALSE ) { /* Handle error */ + Error("Error restarting zmfilter.pl using $url"); + } + } catch ( Exception $e ) { + Error("Except $e thrown trying to restart zmfilter"); + } + } # end if local or remote + } # end foreach erver + } # end function control + } # end class Filter ?> diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php index 782d93885..4dc595470 100644 --- a/web/includes/actions/filter.php +++ b/web/includes/actions/filter.php @@ -30,9 +30,23 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } elseif ( $action == 'delterm' ) { $_REQUEST['filter'] = delFilterTerm($_REQUEST['filter'], $_REQUEST['line']); } else if ( canEdit('Events') ) { + if ( empty($_REQUEST['Id']) ) { + Error("No filter id specified."); + return; + } + + require_once('includes/Filter.php'); + $filter = new Filter($_REQUEST['Id']); + if ( $action == 'delete' ) { if ( !empty($_REQUEST['Id']) ) { - dbQuery('DELETE FROM Filters WHERE Id=?', array($_REQUEST['Id'])); + if ( $filter->Background() ) { + $filter->control('stop'); + } + $filter->delete(); + + } else { + Error("No filter id passed when deleting"); } } else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) { @@ -66,15 +80,30 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) { dbQuery('UPDATE Filters SET '.$sql.' WHERE Id=?', array($_REQUEST['Id'])); + if ( $filter->Background() ) + $filter->control('stop'); } else { dbQuery('INSERT INTO Filters SET'.$sql); $_REQUEST['Id'] = dbInsertId(); + $filter = new Filter($_REQUEST['Id']); } + if ( !empty($_REQUEST['filter']['Background']) ) + $filter->control('start'); + if ( $action == 'execute' ) { executeFilter($_REQUEST['Id']); $view = 'events'; } + } else if ( $action == 'control' ) { + if ( $_REQUEST['command'] == 'start' + or $_REQUEST['command'] == 'stop' + or $_REQUEST['command'] == 'restart' + ) { + $filter->control($_REQUEST['command'], $_REQUEST['ServerId']); + } else { + Error('Invalid command for filter ('.$_REQUEST['command'].')'); + } } // end if save or execute } // end if canEdit(Events) } // end if object == filter From 40e00192679e5592f4496ba0d14a6c4ef3718a55 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 14:15:24 -0500 Subject: [PATCH 55/92] fix all the nav missing when a users Monitors Permission is None --- web/skins/classic/includes/functions.php | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 063977942..c83c2ef34 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -258,10 +258,11 @@ function getNavBarHTML($reload = null) {
> network_check ".$bandwidth_options[$_COOKIE['zmBandwidth']] . ' ', ($user && $user['MaxBandwidth'] != 'low' ) ) ?>
- v'.ZM_VERSION.'', canEdit( 'System' ) ) ?> + v'.ZM_VERSION.'', canEdit('System') ) ?>
  • trending_up :
  • @@ -366,9 +366,9 @@ if ($reload == 'reload') ob_start(); $func = function($S){ $class = ''; if ( $S->disk_usage_percent() > 98 ) { - $class = "error"; + $class = 'error'; } else if ( $S->disk_usage_percent() > 90 ) { - $class = "warning"; + $class = 'warning'; } $title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()). ( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' ); From 5a924ab17680019f07659f0eaa71c813518ad8bc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 16:29:19 -0500 Subject: [PATCH 56/92] cleanup redundant code and spacing --- web/views/image.php | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/web/views/image.php b/web/views/image.php index baa8b94cb..6d25eeb7c 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -78,16 +78,12 @@ if ( empty($_REQUEST['path']) ) { } if ( $_REQUEST['fid'] == 'objdetect' ) { - $Event = new Event($_REQUEST['eid']); - $path = $Event->Path().'/objdetect.jpg'; - unset($Event); # we don't want event object related processing later for this case - if ( !file_exists($path)) { + $path = $Event->Path().'/objdetect.jpg'; + if ( !file_exists($path)) { header('HTTP/1.0 404 Not Found'); - Fatal("File ".$path." does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); } - - } - else if ( $_REQUEST['fid'] == 'alarm' ) { + } else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), array('order'=>'FrameId ASC')); @@ -107,8 +103,7 @@ if ( empty($_REQUEST['path']) ) { } else { $path = $Event->Path().'/alarm.jpg'; } - } - else if ( $_REQUEST['fid'] == 'snapshot' ) { + } else if ( $_REQUEST['fid'] == 'snapshot' ) { $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Score'=>$Event->MaxScore())); if ( !$Frame ) $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'])); From ed6b22ac0681861018fc041e4d9e92ccb996fcb0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 16:29:36 -0500 Subject: [PATCH 57/92] spacing --- src/zm_videostore.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index cb7bac722..e96072664 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -971,7 +971,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(5, "after init packet"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { + if ( (ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); @@ -980,8 +980,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { // av_frame_unref( out_frame ); - if ((ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0) { - if (AVERROR(EAGAIN) == ret) { + if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { + if ( AVERROR(EAGAIN) == ret ) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", av_make_error_string(ret).c_str()); @@ -995,8 +995,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { return 0; } #else - if ((ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, - &data_present)) < 0) { + if ( (ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, + &data_present)) < 0 ) { Error("Could not encode frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); From 5ce681b463dc15dc45fd5f4d26ae981a61fc4dc0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 Feb 2019 16:37:22 -0500 Subject: [PATCH 58/92] instantiate a false Frame object with id = objectect --- web/views/image.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/views/image.php b/web/views/image.php index 6d25eeb7c..968853493 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -79,10 +79,12 @@ if ( empty($_REQUEST['path']) ) { if ( $_REQUEST['fid'] == 'objdetect' ) { $path = $Event->Path().'/objdetect.jpg'; - if ( !file_exists($path)) { + if ( !file_exists($path) ) { header('HTTP/1.0 404 Not Found'); Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); } + $Frame = new Frame(); + $Frame->Id('objdetect'); } else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), From f95e9c0363da863aa7091160421b9163ae2168ec Mon Sep 17 00:00:00 2001 From: timwsuqld Date: Tue, 12 Feb 2019 08:14:33 +1000 Subject: [PATCH 59/92] Fix comment about hiding navbar (#2521) Fixes #2520 --- web/skins/classic/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index c83c2ef34..920d1b9fe 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -219,7 +219,7 @@ function getBodyTopHTML() { } // end function getBodyTopHTML function getNavBarHTML($reload = null) { - # Provide a facility to turn off the headers if you put headers=0 into the url + # Provide a facility to turn off the headers if you put navbar=0 into the url if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar']=='0' ) return ''; From 5b9bb93703198be2e03665333d4d9ab3b27fc699 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 13:17:55 -0500 Subject: [PATCH 60/92] fix navbar auth --- web/skins/classic/includes/functions.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index c83c2ef34..d7d5c3b43 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -259,6 +259,7 @@ function getNavBarHTML($reload = null) { +
    > From 3177764db450084d487e624294938f35d5341215 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 14:20:33 -0500 Subject: [PATCH 61/92] spacing --- src/zm_videostore.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e96072664..34fb7f17c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -891,7 +891,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } ret = avcodec_receive_frame(audio_in_ctx, in_frame); - if (ret < 0) { + if ( ret < 0 ) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } @@ -926,25 +926,23 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples); - if ( #if defined(HAVE_LIBSWRESAMPLE) - (ret = swr_convert(resample_ctx, - out_frame->data, frame_size, - (const uint8_t**)in_frame->data, - in_frame->nb_samples)) + (ret = swr_convert(resample_ctx, + out_frame->data, frame_size, + (const uint8_t**)in_frame->data, + in_frame->nb_samples)); #else #if defined(HAVE_LIBAVRESAMPLE) (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) + 0, in_frame->nb_samples)) + #endif #endif - #endif - < 0) { + av_frame_unref(in_frame); + if ( ret < 0 ) { Error("Could not resample frame (error '%s')", av_make_error_string(ret).c_str()); - av_frame_unref(in_frame); return 0; } - av_frame_unref(in_frame); #if defined(HAVE_LIBAVRESAMPLE) int samples_available = avresample_available(resample_ctx); From 9a0f3801deb90d8cea82540a7f5203acf867def7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 16:25:31 -0500 Subject: [PATCH 62/92] fix + instead of . --- web/views/image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/views/image.php b/web/views/image.php index 968853493..b30d99ba6 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -92,7 +92,7 @@ if ( empty($_REQUEST['path']) ) { if ( !$Frame ) { # no alarms, get first one I find $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'])); if ( !$Frame ) { - Warning("No frame found for event " + $_REQUEST['eid']); + Warning('No frame found for event '.$_REQUEST['eid']); $Frame = new Frame(); $Frame->Delta(1); $Frame->FrameId(1); From 0bfaf87d273b20b32d4f6508eea603ffdcd08221 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 16:40:27 -0500 Subject: [PATCH 63/92] Mostly code style and whitespacing. However, I do setup more values in the output frame when doing audio resampling --- src/zm_videostore.cpp | 90 +++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 34fb7f17c..83e44bfcc 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -31,17 +31,21 @@ extern "C" { #include "libavutil/time.h" } -VideoStore::VideoStore(const char *filename_in, const char *format_in, - AVStream *p_video_in_stream, - AVStream *p_audio_in_stream, int64_t nStartTime, - Monitor *monitor) { +VideoStore::VideoStore( + const char *filename_in, + const char *format_in, + AVStream *p_video_in_stream, + AVStream *p_audio_in_stream, + int64_t nStartTime, + Monitor *monitor + ) { video_in_stream = p_video_in_stream; audio_in_stream = p_audio_in_stream; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); - avcodec_parameters_to_context(video_in_ctx, - video_in_stream->codecpar); + avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); + video_in_ctx->time_base = video_in_stream->time_base; // zm_dump_codecpar( video_in_stream->codecpar ); #else video_in_ctx = video_in_stream->codec; @@ -91,18 +95,17 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_out_ctx = avcodec_alloc_context3(NULL); // Copy params from instream to ctx - ret = avcodec_parameters_to_context(video_out_ctx, - video_in_stream->codecpar); - if (ret < 0) { - Error("Could not initialize ctx parameteres"); + ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); + if ( ret < 0 ) { + Error("Could not initialize video_out_ctx parameters"); return; } else { zm_dump_codec(video_out_ctx); } video_out_stream = avformat_new_stream(oc, NULL); - if (!video_out_stream) { - Error("Unable to create video out stream\n"); + if ( !video_out_stream ) { + Error("Unable to create video out stream"); return; } else { Debug(2, "Success creating video out stream"); @@ -117,7 +120,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, // Now copy them to the out stream ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); - if (ret < 0) { + if ( ret < 0 ) { Error("Could not initialize stream parameteres"); return; } else { @@ -143,7 +146,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, } else { Debug(3, "Success copying ctx"); } - if (!video_out_ctx->codec_tag) { + if ( !video_out_ctx->codec_tag ) { Debug(2, "No codec_tag"); if (!oc->oformat->codec_tag || av_codec_get_id(oc->oformat->codec_tag, @@ -182,17 +185,17 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, } Monitor::Orientation orientation = monitor->getOrientation(); - if (orientation) { - if (orientation == Monitor::ROTATE_0) { + if ( orientation ) { + if ( orientation == Monitor::ROTATE_0 ) { } else if (orientation == Monitor::ROTATE_90) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if (orientation == Monitor::ROTATE_180) { + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_180 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if (orientation == Monitor::ROTATE_270) { + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_270 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); } else { Warning("Unsupported Orientation(%d)", orientation); } @@ -209,13 +212,14 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, resample_ctx = NULL; #endif - if (audio_in_stream) { + if ( audio_in_stream ) { Debug(3, "Have audio stream"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_ctx = avcodec_alloc_context3(NULL); ret = avcodec_parameters_to_context(audio_in_ctx, audio_in_stream->codecpar); + audio_in_ctx->time_base = audio_in_stream->time_base; #else audio_in_ctx = audio_in_stream->codec; #endif @@ -225,7 +229,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); Debug(2, "Got something other than AAC (%s)", error_buffer); - if (!setup_resampler()) { + if ( !setup_resampler() ) { return; } } else { @@ -540,7 +544,8 @@ bool VideoStore::setup_resampler() { audio_out_ctx = audio_out_stream->codec; #endif // Some formats (i.e. WAV) do not produce the proper channel layout - if ( audio_in_ctx->channel_layout == 0 ) + // Perhaps we should not be modifying the audio_in_ctx.... + if ( audio_in_ctx->channel_layout == 0 ) audio_in_ctx->channel_layout = av_get_channel_layout("mono"); /* put sample parameters */ @@ -553,7 +558,7 @@ bool VideoStore::setup_resampler() { #else audio_out_ctx->refcounted_frames = 1; #endif - if ( ! audio_out_ctx->channel_layout ) { + if ( !audio_out_ctx->channel_layout ) { Debug(3, "Correcting channel layout from (%d) to (%d)", audio_out_ctx->channel_layout, av_get_default_channel_layout(audio_out_ctx->channels) @@ -635,10 +640,10 @@ bool VideoStore::setup_resampler() { #if defined(HAVE_LIBSWRESAMPLE) resample_ctx = swr_alloc_set_opts(NULL, - av_get_default_channel_layout(audio_out_ctx->channels), + audio_out_ctx->channel_layout, audio_out_ctx->sample_fmt, audio_out_ctx->sample_rate, - av_get_default_channel_layout(audio_in_ctx->channels), + audio_in_ctx->channel_layout, audio_in_ctx->sample_fmt, audio_in_ctx->sample_rate, 0, NULL); @@ -695,7 +700,9 @@ bool VideoStore::setup_resampler() { out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->format = audio_out_ctx->sample_fmt; + out_frame->channels = audio_out_ctx->channels; out_frame->channel_layout = audio_out_ctx->channel_layout; + out_frame->sample_rate = audio_out_ctx->sample_rate; // The codec gives us the frame size, in samples, we calculate the size of the // samples buffer in bytes @@ -713,10 +720,11 @@ bool VideoStore::setup_resampler() { } // Setup the data pointers in the AVFrame - if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, - audio_out_ctx->sample_fmt, - (const uint8_t *)converted_in_samples, - audioSampleBuffer_size, 0) < 0) { + if ( avcodec_fill_audio_frame( + out_frame, audio_out_ctx->channels, + audio_out_ctx->sample_fmt, + (const uint8_t *)converted_in_samples, + audioSampleBuffer_size, 0) < 0) { Error("Could not allocate converted in sample pointers"); return false; } @@ -896,10 +904,14 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { return 0; } Debug(2, - "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " - "layout(%d)", - in_frame->nb_samples, in_frame->format, - in_frame->sample_rate, in_frame->channel_layout); + "In Frame: samples(%d), format(%d), sample_rate(%d), " + "channels(%d) channel layout(%d) pts(%" PRId64 ")", + in_frame->nb_samples, + in_frame->format, + in_frame->sample_rate, + in_frame->channels, + in_frame->channel_layout, + in_frame->pts); #else /** * Decode the audio frame stored in the packet. @@ -961,9 +973,13 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } #endif Debug(2, - "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + "Out Frame: samples(%d), format(%d), sample_rate(%d), " + "channels(%d) channel layout(%d) pts(%" PRId64 ")", out_frame->nb_samples, out_frame->format, - out_frame->sample_rate, out_frame->channel_layout); + out_frame->sample_rate, + out_frame->channels, + out_frame->channel_layout, + out_frame->pts); av_init_packet(&opkt); Debug(5, "after init packet"); From 7a8668ea99e9351e3ede943a80c75a3e7829cb11 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 16:40:48 -0500 Subject: [PATCH 64/92] whitespace --- web/skins/classic/views/control.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/views/control.php b/web/skins/classic/views/control.php index 0b52641ea..0e5561544 100644 --- a/web/skins/classic/views/control.php +++ b/web/skins/classic/views/control.php @@ -18,7 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canView( 'Control' ) ) { +if ( !canView('Control') ) { $view = 'error'; return; } @@ -26,16 +26,16 @@ if ( !canView( 'Control' ) ) { $params = array(); $groupSql = ''; if ( !empty($_REQUEST['group']) ) { - $groupSql = " AND gm.GroupId = :groupid"; - $params[":groupid"] = $_REQUEST['group']; + $groupSql = ' AND gm.GroupId = :groupid'; + $params[':groupid'] = $_REQUEST['group']; } $mid = !empty($_REQUEST['mid']) ? validInt($_REQUEST['mid']) : 0; $sql = "SELECT m.* FROM Monitors m INNER JOIN Groups_Monitors AS gm ON m.Id = gm.MonitorId WHERE m.Function != 'None' AND m.Controllable = 1$groupSql ORDER BY Sequence"; $mids = array(); -foreach( dbFetchAll( $sql, false, $params ) as $row ) { - if ( !visibleMonitor( $row['Id'] ) ) { +foreach ( dbFetchAll($sql, false, $params) as $row ) { + if ( !visibleMonitor($row['Id']) ) { continue; } if ( empty($mid) ) @@ -43,14 +43,14 @@ foreach( dbFetchAll( $sql, false, $params ) as $row ) { $mids[$row['Id']] = $row['Name']; } -foreach ( getSkinIncludes( 'includes/control_functions.php' ) as $includeFile ) +foreach ( getSkinIncludes('includes/control_functions.php') as $includeFile ) require_once $includeFile; -$monitor = new Monitor( $mid ); +$monitor = new Monitor($mid); $focusWindow = true; -xhtmlHeaders(__FILE__, translate('Control') ); +xhtmlHeaders(__FILE__, translate('Control')); ?>
    @@ -62,13 +62,13 @@ xhtmlHeaders(__FILE__, translate('Control') );
    - +
    - +
    From b6a0e704d202706d167c59cfd9bedfc052fa7b6e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Feb 2019 16:41:08 -0500 Subject: [PATCH 65/92] whitespace, remove xhtml cruft --- web/skins/classic/includes/functions.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index aace3d073..152d85b38 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -91,7 +91,7 @@ echo output_link_if_exists( array( Date: Tue, 12 Feb 2019 17:56:40 -0500 Subject: [PATCH 66/92] Fixes #2375 (#2376) * updated docs to include instructions on how to find the loaded PHP config file * Added note about verifying timezone change * revert docs back to master branch's content * added installation guide for Ubuntu 18.04 The only difference between Ubuntu 16.04 and 18.04 is the version of PHP that comes installed, which changes the location of its config file * reverting debian instructions to master --- docs/installationguide/ubuntu.rst | 199 ++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/docs/installationguide/ubuntu.rst b/docs/installationguide/ubuntu.rst index 6c686d7ed..582b8e5c5 100644 --- a/docs/installationguide/ubuntu.rst +++ b/docs/installationguide/ubuntu.rst @@ -3,6 +3,205 @@ Ubuntu .. contents:: +Easy Way: Ubuntu 18.04 +---------------------- +These instructions are for a brand new ubuntu 18.04 system which does not have ZM +installed. + + +It is recommended that you use an Ubuntu Server install and select the LAMP option +during install to install Apache, MySQL and PHP. If you failed to do this you can +achieve the same result by running: + +:: + + sudo tasksel install lamp-server + +During installation it will ask you to set up a master/root password for the MySQL. +Installing LAMP is not ZoneMinder specific so you will find plenty of resources to +guide you with a quick search. + +**Step 1:** Either run commands in this install using sudo or use the below to become root +:: + + sudo -i + +**Step 2:** Update Repos + +.. topic :: Latest Release + + ZoneMinder is now part of the current standard Ubuntu repository, but + sometimes the official repository can lag behind. To find out check our + `releases page `_ for + the latest release. + + Alternatively, the ZoneMinder project team maintains a `PPA `_, which is updated immediately + following a new release of ZoneMinder. To use this repository instead of the + official Ubuntu repository, enter the following from the command line: + + :: + + add-apt-repository ppa:iconnor/zoneminder + + Please note that as of 1.32.0 We are creating a new PPA for each major version, as a means to prevent automatic upgrades from one major version to another. So instead of the above ppa line use the following: + + :: + + add-apt-repository ppa:iconnor/zoneminder-1.32 + + If you are on Trusty or Xenial, you may want to add both, as there are some packages for dependencies included in the old ppa. + + +Update repo and upgrade. + +:: + + apt-get update + apt-get upgrade + apt-get dist-upgrade + + +**Step 3:** Configure MySQL + +.. sidebar :: Note + + The MySQL default configuration file (/etc/mysql/mysql.cnf)is read through + several symbolic links beginning with /etc/mysql/my.cnf as follows: + + | /etc/mysql/my.cnf -> /etc/alternatives/my.cnf + | /etc/alternatives/my.cnf -> /etc/mysql/mysql.cnf + | /etc/mysql/mysql.cnf is a basic file + +Certain new defaults in MySQL 5.7 cause some issues with ZoneMinder < 1.32.0, +the workaround is to modify the sql_mode setting of MySQL. Please note that these +changes are NOT required for ZoneMinder 1.32.0 and some people have reported them +causing problems in 1.32.0. + +To better manage the MySQL server it is recommended to copy the sample config file and +replace the default my.cnf symbolic link. + +:: + + rm /etc/mysql/my.cnf (this removes the current symbolic link) + cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/my.cnf + +To change MySQL settings: + +:: + + nano /etc/mysql/my.cnf + +In the [mysqld] section add the following + +:: + + sql_mode = NO_ENGINE_SUBSTITUTION + +CTRL+o then [Enter] to save + +CTRL+x to exit + +Restart MySQL + +:: + + systemctl restart mysql + + +**Step 4:** Install ZoneMinder + +:: + + apt-get install zoneminder + +**Step 5:** Configure the ZoneMinder Database + +This step should not be required on ZoneMinder 1.32.0. + +:: + + mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql + mysql -uroot -p -e "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on zm.* to 'zmuser'@localhost identified by 'zmpass';" + + +**Step 6:** Set permissions + +Set /etc/zm/zm.conf to root:www-data 740 and www-data access to content + +:: + + chmod 740 /etc/zm/zm.conf + chown root:www-data /etc/zm/zm.conf + chown -R www-data:www-data /usr/share/zoneminder/ + +**Step 7:** Configure Apache correctly: + +:: + + a2enmod cgi + a2enmod rewrite + a2enconf zoneminder + +You may also want to enable to following modules to improve caching performance + +:: + + a2enmod expires + a2enmod headers + +**Step 8:** Enable and start Zoneminder + +:: + + systemctl enable zoneminder + systemctl start zoneminder + +**Step 9:** Edit Timezone in PHP + +:: + + nano /etc/php/7.2/apache2/php.ini + +Search for [Date] (Ctrl + w then type Date and press Enter) and change +date.timezone for your time zone, see [this](http://php.net/manual/en/timezones.php). +**Don't forget to remove the ; from in front of date.timezone** + +:: + + [Date] + ; Defines the default timezone used by the date functions + ; http://php.net/date.timezone + date.timezone = America/New_York + +CTRL+o then [Enter] to save + +CTRL+x to exit + +**Step 10:** Reload Apache service + +:: + + systemctl reload apache2 + +**Step 11:** Making sure ZoneMinder works + +1. Open up a browser and go to ``http://hostname_or_ip/zm`` - should bring up ZoneMinder Console + +2. (Optional API Check)Open up a tab in the same browser and go to ``http://hostname_or_ip/zm/api/host/getVersion.json`` + + If it is working correctly you should get version information similar to the example below: + + :: + + { + "version": "1.29.0", + "apiversion": "1.29.0.1" + } + +**Congratulations** Your installation is complete + +PPA install may need some tweaking of ZMS_PATH in ZoneMinder options. `Socket_sendto or no live streaming`_ + Easy Way: Ubuntu 16.04 ---------------------- These instructions are for a brand new ubuntu 16.04 system which does not have ZM From 924d5235d0ba93f88eafcd99f546ec06c36ecac3 Mon Sep 17 00:00:00 2001 From: Steve Gilvarry Date: Thu, 14 Feb 2019 02:40:43 +1100 Subject: [PATCH 67/92] Validate zmu Username and Password lengths (#2484) * Validate zmu Username and Password lengths Ensure user provided values are not larger than allowed and error if they are, therefore further preventing overflow. * Check username and password functions for zmu and zms * Check username and password functions for zmu and zms --- src/zm_user.cpp | 15 +++++++++++++++ src/zm_user.h | 2 ++ src/zms.cpp | 5 ++++- src/zmu.cpp | 13 ++++++++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 6dbfb56fa..da0c66416 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -245,3 +245,18 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { Debug(1, "No user found for auth_key %s", auth ); return 0; } + +//Function to check Username length +bool checkUser ( const char *username) { + if ( strlen(username) > 32) { + return false; + } + return true; +} +//Function to check password length +bool checkPass (const char *password) { + if ( strlen(password) > 64) { + return false; + } + return true; +} diff --git a/src/zm_user.h b/src/zm_user.h index 37bf45736..00c61185b 100644 --- a/src/zm_user.h +++ b/src/zm_user.h @@ -77,5 +77,7 @@ public: User *zmLoadUser( const char *username, const char *password=0 ); User *zmLoadAuthUser( const char *auth, bool use_remote_addr ); +bool checkUser ( const char *username); +bool checkPass (const char *password); #endif // ZM_USER_H diff --git a/src/zms.cpp b/src/zms.cpp index a5fef0134..634e07030 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -191,9 +191,12 @@ int main( int argc, const char *argv[] ) { User *user = 0; if ( strcmp(config.auth_relay, "none") == 0 ) { - if ( username.length() ) { + if ( checkUser(username.c_str()) ) { user = zmLoadUser(username.c_str()); + } else { + Error("") } + } else { //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) { diff --git a/src/zmu.cpp b/src/zmu.cpp index af6cb603d..a8ee61273 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -425,6 +425,10 @@ int main(int argc, char *argv[]) { if ( config.opt_use_auth ) { if ( strcmp(config.auth_relay, "none") == 0 ) { + if ( !checkUser(username)) { + fprintf(stderr, "Error, username greater than allowed 32 characters\n"); + exit_zmu(-1); + } if ( !username ) { fprintf(stderr, "Error, username must be supplied\n"); exit_zmu(-1); @@ -438,7 +442,14 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Error, username and password or auth string must be supplied\n"); exit_zmu(-1); } - + if ( !checkUser(username)) { + fprintf(stderr, "Error, username greater than allowed 32 characters\n"); + exit_zmu(-1); + } + if ( !checkPass(password)) { + fprintf(stderr, "Error, password greater than allowed 64 characters\n"); + exit_zmu(-1); + } //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) { if ( auth ) { From 400d4dc27e2aec72371cc8b4897c2498b8252c3f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 Feb 2019 11:24:09 -0500 Subject: [PATCH 68/92] encode the label on the preset so that weird characters and quotes don't break the button --- web/skins/classic/includes/control_functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 6274afae5..ec51458ee 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -270,7 +270,7 @@ function controlPresets( $monitor, $cmds ) { NumPresets(); $i++ ) { ?> - " value="" onclick="controlCmd('');"/> +
    Date: Wed, 13 Feb 2019 11:52:16 -0500 Subject: [PATCH 69/92] fix path to Control.php --- web/includes/actions/controlcap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/actions/controlcap.php b/web/includes/actions/controlcap.php index ec21e0dcd..71b59e1b6 100644 --- a/web/includes/actions/controlcap.php +++ b/web/includes/actions/controlcap.php @@ -25,7 +25,7 @@ if ( !canEdit('Control') ) { } // end if !canEdit Controls if ( $action == 'controlcap' ) { - require_once('Control.php'); + require_once('includes/Control.php'); $Control = new Control( !empty($_REQUEST['cid']) ? $_REQUEST['cid'] : null ); //$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns ); From 419e60e8b4cef9d9dea065907bc5a692201d318e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 Feb 2019 16:55:40 -0500 Subject: [PATCH 70/92] Allow negative DiskSpace values. Technically shouldn't happen but since we don't have foreign keys yet, it can happen --- db/zm_create.sql.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 4e6a6646c..2fed4b7d0 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -223,7 +223,7 @@ CREATE TABLE `Events_Hour` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, + `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Hour_MonitorId_idx` (`MonitorId`), KEY `Events_Hour_StartTime_idx` (`StartTime`) @@ -234,7 +234,7 @@ CREATE TABLE `Events_Day` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, + `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Day_MonitorId_idx` (`MonitorId`), KEY `Events_Day_StartTime_idx` (`StartTime`) @@ -245,7 +245,7 @@ CREATE TABLE `Events_Week` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, + `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Week_MonitorId_idx` (`MonitorId`), KEY `Events_Week_StartTime_idx` (`StartTime`) @@ -256,7 +256,7 @@ CREATE TABLE `Events_Month` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, + `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Month_MonitorId_idx` (`MonitorId`), KEY `Events_Month_StartTime_idx` (`StartTime`) @@ -267,7 +267,7 @@ DROP TABLE IF EXISTS `Events_Archived`; CREATE TABLE `Events_Archived` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, - `DiskSpace` bigint unsigned default NULL, + `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Archived_MonitorId_idx` (`MonitorId`) ) ENGINE=@ZM_MYSQL_ENGINE@; From 512a6e19dec19a4171bee6a35f6333330acb7e34 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 Feb 2019 16:55:55 -0500 Subject: [PATCH 71/92] bump version --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 02261bead..80c8c0bd3 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.33.1 +1.33.2 From d3a811738582929bceef15d0df1747743b7fe836 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 Feb 2019 20:38:13 -0500 Subject: [PATCH 72/92] add missing db update script --- db/zm_update-1.33.2.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 db/zm_update-1.33.2.sql diff --git a/db/zm_update-1.33.2.sql b/db/zm_update-1.33.2.sql new file mode 100644 index 000000000..ea0237b7e --- /dev/null +++ b/db/zm_update-1.33.2.sql @@ -0,0 +1,13 @@ +-- +-- This updates a 1.33.0 database to 1.33.1 +-- +-- Add WebSite enum to Monitor.Type +-- Add Refresh column to Monitors table +-- + +ALTER TABLE `Events_Hour` MODIFY DiskSpace BIGINT default NULL; +ALTER TABLE `Events_Day` MODIFY DiskSpace BIGINT default NULL; +ALTER TABLE `Events_Week` MODIFY DiskSpace BIGINT default NULL; +ALTER TABLE `Events_Month` MODIFY DiskSpace BIGINT default NULL; +ALTER TABLE `Events_Archived` MODIFY DiskSpace BIGINT default NULL; + From 62bf7d54f17064a7ebfcbf494947501ad5faed7f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 Feb 2019 15:40:42 -0500 Subject: [PATCH 73/92] close sth's on Fatal to prevent error message --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index eb7a8824d..35d505b75 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -696,10 +696,15 @@ sub error { } sub Fatal( @ ) { - fetch()->logPrint(FATAL, @_, caller); + my $this = fetch(); + $this->logPrint(FATAL, @_, caller); if ( $SIG{TERM} and ( $SIG{TERM} ne 'DEFAULT' ) ) { $SIG{TERM}(); } + if ( $$this{sth} ) { + $$this{sth}->finish(); + $$this{sth} = undef; + } # I think if we don't disconnect we will leave sockets around in TIME_WAIT ZoneMinder::Database::zmDbDisconnect(); exit(-1); From 281775cc801decd1a5af0aad6ff797a5c5f58ea5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 Feb 2019 15:54:47 -0500 Subject: [PATCH 74/92] try setting out_frame pts from in_frame --- src/zm_videostore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 83e44bfcc..fc4a64d2d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -949,6 +949,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { 0, in_frame->nb_samples)) #endif #endif + out_frame->pts = in_frame->pts; av_frame_unref(in_frame); if ( ret < 0 ) { Error("Could not resample frame (error '%s')", From 4e463c93548c4a1afdfc4eb656ea8422d04b6c4c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 Feb 2019 17:48:58 -0500 Subject: [PATCH 75/92] use swr_convert_frame instead of swr_convert --- src/zm_videostore.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index fc4a64d2d..e6cd5e13e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -939,17 +939,23 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { // decoded data Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples); #if defined(HAVE_LIBSWRESAMPLE) - (ret = swr_convert(resample_ctx, +#if 0 + ret = swr_convert(resample_ctx, out_frame->data, frame_size, (const uint8_t**)in_frame->data, - in_frame->nb_samples)); + in_frame->nb_samples + ); +#else + ret = swr_convert_frame(resample_ctx, out_frame, in_frame); + +#endif #else #if defined(HAVE_LIBAVRESAMPLE) (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, 0, in_frame->nb_samples)) #endif #endif - out_frame->pts = in_frame->pts; +//out_frame->pts = in_frame->pts; av_frame_unref(in_frame); if ( ret < 0 ) { Error("Could not resample frame (error '%s')", From 96906734b8c62d7e9d16c8df351b2ef5bb704549 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 Feb 2019 17:26:30 -0500 Subject: [PATCH 76/92] add an audio_fifo to handle input audio < 1024 samples per frame --- src/zm_videostore.cpp | 76 ++++++++++++++++++++++++++++++++++--------- src/zm_videostore.h | 2 ++ 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e6cd5e13e..b38e4dbd6 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -210,6 +210,9 @@ VideoStore::VideoStore( out_frame = NULL; #if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) resample_ctx = NULL; +#if defined(HAVE_LIBSWRESAMPLE) + fifo = NULL; +#endif #endif if ( audio_in_stream ) { @@ -415,7 +418,7 @@ VideoStore::~VideoStore() { Debug(1,"Writing trailer"); /* Write the trailer before close */ - if (int rc = av_write_trailer(oc)) { + if ( int rc = av_write_trailer(oc) ) { Error("Error writing trailer %s", av_err2str(rc)); } else { Debug(3, "Success Writing trailer"); @@ -471,6 +474,10 @@ VideoStore::~VideoStore() { #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) if ( resample_ctx ) { #if defined(HAVE_LIBSWRESAMPLE) + if ( fifo ) { + av_audio_fifo_free(fifo); + fifo = NULL; + } swr_free(&resample_ctx); #else #if defined(HAVE_LIBAVRESAMPLE) @@ -618,6 +625,12 @@ bool VideoStore::setup_resampler() { } #endif + Debug(1, + "Audio in bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_in_ctx->bit_rate, audio_in_ctx->sample_rate, + audio_in_ctx->channels, audio_in_ctx->sample_fmt, + audio_in_ctx->channel_layout, audio_in_ctx->frame_size); Debug(1, "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " "layout(%d) frame_size(%d)", @@ -639,6 +652,12 @@ bool VideoStore::setup_resampler() { } #if defined(HAVE_LIBSWRESAMPLE) + if (!(fifo = av_audio_fifo_alloc( + audio_out_ctx->sample_fmt, + audio_out_ctx->channels, 1))) { + Error("Could not allocate FIFO"); + return false; + } resample_ctx = swr_alloc_set_opts(NULL, audio_out_ctx->channel_layout, audio_out_ctx->sample_fmt, @@ -933,11 +952,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { return 0; } #endif - int frame_size = out_frame->nb_samples; + int frame_size = in_frame->nb_samples; // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data - Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples); + Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples); #if defined(HAVE_LIBSWRESAMPLE) #if 0 ret = swr_convert(resample_ctx, @@ -946,24 +965,50 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { in_frame->nb_samples ); #else - ret = swr_convert_frame(resample_ctx, out_frame, in_frame); - -#endif - #else - #if defined(HAVE_LIBAVRESAMPLE) - (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) - #endif - #endif -//out_frame->pts = in_frame->pts; + ret = swr_convert_frame(resample_ctx, out_frame, in_frame); av_frame_unref(in_frame); if ( ret < 0 ) { Error("Could not resample frame (error '%s')", av_make_error_string(ret).c_str()); return 0; } +#endif + if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) { + Error("Could not reallocate FIFO"); + return 0; + } + /** Store the new samples in the FIFO buffer. */ + ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples); + if ( ret < frame_size ) { + Error("Could not write data to FIFO on %d written", ret); + return 0; + } - #if defined(HAVE_LIBAVRESAMPLE) + // Reset frame_size to output_frame_size + frame_size = audio_out_ctx->frame_size; + + // AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them. + if ( frame_size > av_audio_fifo_size(fifo) ) { + return 0; + } + + if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) { + Error("Could not read data from FIFO"); + return 0; + } + out_frame->nb_samples = frame_size; + /// FIXME this is not the correct pts + out_frame->pts = in_frame->pts; + #else + #if defined(HAVE_LIBAVRESAMPLE) + (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + 0, in_frame->nb_samples)) + av_frame_unref(in_frame); + if ( ret < 0 ) { + Error("Could not resample frame (error '%s')", + av_make_error_string(ret).c_str()); + return 0; + } int samples_available = avresample_available(resample_ctx); if ( samples_available < frame_size ) { @@ -978,6 +1023,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Warning("Error reading resampled audio:"); return 0; } + #endif #endif Debug(2, "Out Frame: samples(%d), format(%d), sample_rate(%d), " @@ -1003,7 +1049,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { if ( AVERROR(EAGAIN) == ret ) { - // THe codec may need more samples than it has, perfectly valid + // The codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", av_make_error_string(ret).c_str()); } else { diff --git a/src/zm_videostore.h b/src/zm_videostore.h index bc7cd8417..ef0093706 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -5,6 +5,7 @@ extern "C" { #ifdef HAVE_LIBSWRESAMPLE #include "libswresample/swresample.h" + #include "libavutil/audio_fifo.h" #else #ifdef HAVE_LIBAVRESAMPLE #include "libavresample/avresample.h" @@ -44,6 +45,7 @@ private: AVCodecContext *audio_out_ctx; #ifdef HAVE_LIBSWRESAMPLE SwrContext *resample_ctx; + AVAudioFifo *fifo; #else #ifdef HAVE_LIBAVRESAMPLE AVAudioResampleContext* resample_ctx; From 34873d5636e1642dc38b80de61d04a2e709c6fcd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 16 Feb 2019 11:50:09 -0500 Subject: [PATCH 77/92] We must leave ZM_HOME_CONTENT unescaped so that we can insert actual html like image tags --- web/skins/classic/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 152d85b38..04b87bd33 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -252,7 +252,7 @@ function getNavBarHTML($reload = null) { - +
+ Date: Tue, 19 Feb 2019 10:07:36 -0500 Subject: [PATCH 84/92] Add missing / in path to auth.php --- web/api/app/Controller/HostController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index db6f38523..74ea854a4 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -66,7 +66,7 @@ class HostController extends AppController { if ( $isZmAuth ) { // In future, we may want to completely move to AUTH_HASH_LOGINS and return &auth= for all cases - require_once __DIR__ ."../../../includes/auth.php"; # in the event we directly call getCredentials.json + require_once __DIR__ .'/../../../includes/auth.php'; # in the event we directly call getCredentials.json $this->Session->read('user'); # this is needed for command line/curl to recognize a session $zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value']; if ( $zmAuthRelay == 'hashed' ) { From 8837015239872a59779e2c18115a77c864fd780a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Feb 2019 13:54:25 -0500 Subject: [PATCH 85/92] remove bogus test for Filter Id --- web/includes/actions/filter.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php index 4dc595470..c15f36c65 100644 --- a/web/includes/actions/filter.php +++ b/web/includes/actions/filter.php @@ -30,10 +30,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } elseif ( $action == 'delterm' ) { $_REQUEST['filter'] = delFilterTerm($_REQUEST['filter'], $_REQUEST['line']); } else if ( canEdit('Events') ) { - if ( empty($_REQUEST['Id']) ) { - Error("No filter id specified."); - return; - } require_once('includes/Filter.php'); $filter = new Filter($_REQUEST['Id']); From b3e20c6c5061afe1de584fd39d651e9ece02c339 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Wed, 20 Feb 2019 11:21:15 -0500 Subject: [PATCH 86/92] fix slack join link (#2535) Slack allows its own join portal. I created a permanent link we can use instead of the 3rd party heroku app which is slow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8e3f34fd..b0f4be37b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 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) -[![Join Slack](https://github.com/ozonesecurity/ozonebase/blob/master/img/slacksm.png?raw=true)](https://zoneminder-chat.herokuapp.com) +[![Join Slack](https://github.com/ozonesecurity/ozonebase/blob/master/img/slacksm.png?raw=true)](https://join.slack.com/t/zoneminder-chat/shared_invite/enQtNTU0NDkxMDM5NDQwLTlhZDU2MGU4MmZmN2MxOTg1MmNmNmZjZGRmY2EzMThhNGQ0MWNmZTg1ZmYzNDQ4YjliMzVmYTQ3MDc5MTkzODE) All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org From d93924bd89b4b19703d8357e381482d3ae00de1a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 20 Feb 2019 15:39:26 -0500 Subject: [PATCH 87/92] increase width of controls popup. --- 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 87220a183..b0a28dc96 100644 --- a/web/skins/classic/js/base.js +++ b/web/skins/classic/js/base.js @@ -27,7 +27,7 @@ var popupSizes = { 'bandwidth': {'width': 300, 'height': 200}, 'console': {'width': 750, 'height': 312}, - 'control': {'width': 380, 'height': 480}, + 'control': {'width': 480, 'height': 480}, 'controlcaps': {'width': 780, 'height': 320}, 'controlcap': {'width': 400, 'height': 400}, 'cycle': {'addWidth': 32, 'minWidth': 384, 'addHeight': 62}, From e087522203ec41d490d72e82c7feb1b1dfbcfc66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 21 Feb 2019 14:15:10 -0500 Subject: [PATCH 88/92] remove debug --- web/skins/classic/views/_monitor_filters.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 0656773f1..6f94580e2 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -68,7 +68,6 @@ if ( count($GroupsById) ) { $selected_monitor_ids = isset($_SESSION['MonitorId']) ? $_SESSION['MonitorId'] : array(); if ( ! is_array( $selected_monitor_ids ) ) { - Warning("Turning selected_monitor_ids into an array $selected_monitor_ids"); $selected_monitor_ids = array($selected_monitor_ids); } From b8117f7fc9561ee0d2aa7c245504fe92d13c405e Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 22 Feb 2019 09:17:28 -0500 Subject: [PATCH 89/92] Add support for control of Amcrest cameras (#2536) * Add a control module to support the current Amcrest HTTP API This patch adds ZoneMinder::Control::Amcrest_HTTP This module is adapted and improved from one available on the ZoneMinder forums.[1] It appears that a number of individuals have contributed to it. This is an attempt to correct some of its interactions with ZM::Control and friends as well as enhance and extend supported control features for Amcrest cameras. This work is based on Amcrest HTTP Protocol API Specifications Rev. 2.12 2017-03-15 [1]https://forums.zoneminder.com/download/file.php?id=1878 * Fixing zoom methods * Misc. cleanup of comments, etc. * Fixing up POD, etc. * Converting line endings to Unix * Fixing up preset methods The current Amcrest HTTP API does not support a Home command per se. So this method is set up to send the camera to the first preset position. Of course, this presupposes that the user will setup a preset #1 otherwise the command will fail on a bad preset error. If a future version of the API supports a true Home command, we'll adjust at that point. For now this seems to be a useful workaround. * Removing duplicate home method * Adding moveAbs method I'm putting this in, but absolute camera movement does not seem to be well supported in the classic skin ATM. Reading www/skins/classic/include/control_functions.php seems to indicate a faulty implementation, unless I'm reading it wrong. I see nowhere where the user is able to specify the absolute location to move to. Rather, the call is passed back movement in increments of 1 unit. At least with the Amcrest/Duhua API this would result in the camera moving to the 1* or 0* etc. position. moveAbsUp, Down, Left, Right, etc. Doesn't make sense given the definition of Absolute movement. * Adding a note about the moveMap method This method does not appear to be implemented in the classic skin, but we'll leave it here for future implementation. Caveat: It may or may not work as-is. * Fixing up zoomConTele/Wide methods * Adding a vanilla control type for the Amcrest HTTP API Please note that this control type matches (mostly) the currently available control options in Amcrest_HTTP.pm. It does not match all (or possibly any) of the control options available on a specific Amcrest camera. The user may need to create their own control type specific to the camera model they are using. * Removing misplaced comment Thanks to connortechnology for pointing this out! --- db/zm_create.sql.in | 1 + .../lib/ZoneMinder/Control/Amcrest_HTTP.pm | 403 ++++++++++++++++++ 2 files changed, 404 insertions(+) create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Control/Amcrest_HTTP.pm diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 2fed4b7d0..c4a592897 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -788,6 +788,7 @@ INSERT INTO `Controls` VALUES (NULL,'Trendnet','Remote','Trendnet',1,1,1,0,0,0,0 INSERT INTO `Controls` VALUES (NULL,'PSIA','Remote','PSIA',0,0,0,1,0,0,1,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,1,0,1,0,0,0,0,1,-100,100,0,0,1,0,0,0,0,1,-100,100,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Dahua','Remote','Dahua',0,0,0,1,0,0,1,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'FOSCAMR2C','Libvlc','FOSCAMR2C',1,1,1,0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,1,12,0,1,1,1,0,0,0,1,1,NULL,NULL,NULL,NULL,1,0,4,0,NULL,1,NULL,NULL,NULL,NULL,1,0,4,0,NULL,0,0); +INSERT INTO `Controls` VALUES (NULL,'Amcrest HTTP API','Ffmpeg','Amcrest_HTTP',0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,5); -- -- Add some monitor preset values diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Amcrest_HTTP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Amcrest_HTTP.pm new file mode 100644 index 000000000..7a89f353e --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Amcrest_HTTP.pm @@ -0,0 +1,403 @@ +# ========================================================================== +# +# ZoneMinder Acrest HTTP API Control Protocol Module, 20180214, Rev 3.0 +# +# Change Log +# +# Rev 3.0: +# - Fixes incorrect method names +# - Updates control sequences to Amcrest HTTP Protocol API v 2.12 +# - Extends control features +# +# Rev 2.0: +# - Fixed installation instructions text, no changes to functionality. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ========================================================================== + +package ZoneMinder::Control::Amcrest_HTTP; + +use 5.006; +use strict; +use warnings; + +use Time::HiRes qw( usleep ); + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +# ========================================================================== +# +# Amcrest HTTP API Control Protocol +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Config qw(:all); + +sub new +{ + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + bless( $self, $class ); + srand( time() ); + return $self; +} + +our $AUTOLOAD; + +sub AUTOLOAD +{ + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + Debug( "Received command: $name" ); + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + Fatal( "Can't access $name member of object of class $class" ); +} + +sub open +{ + my $self = shift; + + $self->loadMonitor(); + $self->{state} = 'open'; +} + +sub initUA +{ + my $self = shift; + my $user = undef; + my $password = undef; + my $address = undef; + + if ( $self->{Monitor}->{ControlAddress} =~ /(.*):(.*)@(.*)/ ) + { + $user = $1; + $password = $2; + $address = $3; + } + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->credentials("$address", "Login to " . $self->{Monitor}->{ControlDevice}, "$user", "$password"); + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); +} + +sub destroyUA +{ + my $self = shift; + + $self->{ua} = undef; +} + +sub close +{ + my $self = shift; + $self->{state} = 'closed'; +} + +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; + + destroyUA($self); + initUA($self); + + my $user = undef; + my $password = undef; + my $address = undef; + + if ( $self->{Monitor}->{ControlAddress} =~ /(.*):(.*)@(.*)/ ) + { + $user = $1; + $password = $2; + $address = $3; + } + + printMsg( $cmd, "Tx" ); + + my $req = HTTP::Request->new( GET=>"http://$address/$cmd" ); + my $res = $self->{ua}->request($req); + + if ( $res->is_success ) + { + $result = !undef; + # Command to camera appears successful, write Info item to log + Info( "Camera control: '".$res->status_line()."' for URL ".$self->{Monitor}->{ControlAddress}."/$cmd" ); + # TODO: Add code to retrieve $res->message_decode or some such. Then we could do things like check the camera status. + } + else + { + Error( "Camera control command FAILED: '".$res->status_line()."' for URL ".$self->{Monitor}->{ControlAddress}."/$cmd" ); + } + + return( $result ); +} + +sub reset +{ + my $self = shift; + # This reboots the camera effectively resetting it + Debug( "Camera Reset" ); + $self->sendCmd( 'cgi-bin/magicBox.cgi?action=reboot' ); + ##FIXME: Exit is a bad idea as it appears to cause zmc to run away. + #Exit (0); +} + +# NOTE: I'm putting this in, but absolute camera movement does not seem to be well supported in the classic skin ATM. +# Reading www/skins/classic/include/control_functions.php seems to indicate a faulty implementation, unless I'm +# reading it wrong. I see nowhere where the user is able to specify the absolute location to move to. Rather, +# the call is passed back movement in increments of 1 unit. At least with the Amcrest/Duhua API this would result +# in the camera moving to the 1* or 0* etc. position. + +sub moveAbs ## Up, Down, Left, Right, etc. ??? Doesn't make sense here... +{ + my $self = shift; + my $pan_degrees = shift || 0; + my $tilt_degrees = shift || 0; + my $speed = shift || 1; + Debug( "Move ABS" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=PositionABS&channel=0&arg1='.$pan_degress.'&arg2='.$tilt_degrees.'&arg3=0&arg4='.$speed ); +} + +sub moveConUp +{ + my $self = shift; + Debug( "Move Up" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=Up&channel=0&arg1=0&arg2=1&arg3=0' ); + usleep (500); ##XXX Should this be passed in as a "speed" parameter? + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=Up&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConDown +{ + my $self = shift; + Debug( "Move Down" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=Down&channel=0&arg1=0&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=Down&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConLeft +{ + my $self = shift; + Debug( "Move Left" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=Left&channel=0&arg1=0&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=Left&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConRight +{ + my $self = shift; + Debug( "Move Right" ); +# $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=PositionABS&channel=0&arg1=270&arg2=5&arg3=0' ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=Right&channel=0&arg1=0&arg2=1&arg3=0' ); + usleep (500); + Debug( "Move Right Stop" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=Right&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConUpRight +{ + my $self = shift; + Debug( "Move Diagonally Up Right" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=RightUp&channel=0&arg1=1&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=RightUp&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConDownRight +{ + my $self = shift; + Debug( "Move Diagonally Down Right" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=RightDown&channel=0&arg1=1&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=RightDown&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConUpLeft +{ + my $self = shift; + Debug( "Move Diagonally Up Left" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=LeftUp&channel=0&arg1=1&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=LeftUp&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +sub moveConDownLeft +{ + my $self = shift; + Debug( "Move Diagonally Down Left" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=LeftDown&channel=0&arg1=1&arg2=1&arg3=0' ); + usleep (500); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&code=LeftDown&channel=0&arg1=0&arg2=1&arg3=0' ); +} + +# Stop is not "correctly" implemented as control_functions.php translates this to "Center" +# So we'll just send the camera to 0* Horz, 0* Vert, zoom out; Also, Amcrest does not seem to +# support a generic stop-all-current-action command. + +sub moveStop +{ + my $self = shift; + Debug( "Move Stop/Center" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=PositionABS&channel=0&arg1=0&arg2=0&arg3=0&arg4=1' ); +} + +# Move Camera to Home Position +# The current API does not support a Home per se, so we'll just send the camera to preset #1 +# NOTE: It goes without saying that the user must have set up preset #1 for this to work. + +sub presetHome +{ + my $self = shift; + Debug( "Home Preset" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&channel=0&code=GotoPreset&&arg1=0&arg2=1&arg3=0&arg4=0' ); +} + +sub presetGoto +{ + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Go To Preset $preset" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&channel=0&code=GotoPreset&&arg1=0&arg2='.$preset.'&arg3=0&arg4=0' ); +} + +sub presetSet +{ + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Set Preset" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&channel=0&code=SetPreset&arg1=0&arg2='.$preset.'&arg3=0&arg4=0' ); +} + +# NOTE: This does not appear to be implemented in the classic skin. But we'll leave it here for later. + +sub moveMap +{ + my $self = shift; + my $params = shift; + + my $xcoord = $self->getParam( $params, 'xcoord', $self->{Monitor}{Width}/2 ); + my $ycoord = $self->getParam( $params, 'ycoord', $self->{Monitor}{Height}/2 ); + # if the camera is mounted upside down, you may have to inverse these coordinates + # just use 360 minus pan instead of pan, 90 minus tilt instead of tilt + # Convert xcoord into pan position 0 to 359 + my $pan = int(360 * $xcoord / $self->{Monitor}{Width}); + # Convert ycoord into tilt position 0 to 89 + my $tilt = 90 - int(90 * $ycoord / $self->{Monitor}{Height}); + # Now get the following url: + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&code=PositionABS&channel=0&arg1='.$pan.'&arg2='.$tilt.'&arg3=1&arg4=1'); +} + +sub zoomConTele +{ + my $self = shift; + Debug( "Zoom continuous tele" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&channel=0&code=ZoomTele&arg1=0&arg2=0&arg3=0&arg4=0' ); + usleep (100000); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&channel=0&code=ZoomTele&arg1=0&arg2=0&arg3=0&arg4=0' ); +} + +sub zoomConWide +{ + my $self = shift; + Debug( "Zoom continuous wide" ); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=start&channel=0&code=ZoomWide&arg1=0&arg2=0&arg3=0&arg4=0' ); + usleep (100000); + $self->sendCmd( 'cgi-bin/ptz.cgi?action=stop&channel=0&code=ZoomWide&arg1=0&arg2=0&arg3=0&arg4=0' ); +} + +1; + +__END__ + +=pod + +=head1 NAME + +ZoneMinder::Control::Amcrest_HTTP - Amcrest camera control + +=head1 DESCRIPTION + +This module contains the implementation of the Amcrest Camera +controllable SDK API. + +NOTE: This module implements interaction with the camera in clear text. + +The login and password are transmitted from ZM to the camera in clear text, +and as such, this module should be used ONLY on a blind LAN implementation +where interception of the packets is very low risk. + +The "usleep (X);" lines throughout the script may need adjustments for your +situation. This is the time that the script waits between sending a "start" +and a "stop" signal to the camera. For example, the pan left arrow would +result in the camera panning full to its leftmost position if there were no +stop signal. So the usleep time sets how long the script waits to allow the +camera to start moving before issuing a stop. The X value of usleep is in +microseconds, so "usleep (100000);" is equivalent to wait one second. + +=head1 SEE ALSO + +https://s3.amazonaws.com/amcrest-files/Amcrest+HTTP+API+3.2017.pdf + +=head1 AUTHORS + +Herndon Elliott alabamatoy at gmail dot com +Chris Nighswonger chris dot nighswonger at gmail dot com + +=head1 COPYRIGHT AND LICENSE + +(C) 2016 Herndon Elliott alabamatoy at gmail dot com +(C) 2018 Chris Nighswonger chris dot nighswonger at gmail dot com + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +=cut From 8dd8888975bb2a05feb5fca09fa05c5f34803aa2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 22 Feb 2019 09:19:07 -0500 Subject: [PATCH 90/92] Php namespace (#2537) * experiment with namespaces on the Server class * experiment with namespaces on the Server class * Implement the ZM namespace on objects * Implement the ZM namespace on objects * Implement the ZM namespace on objects --- web/ajax/add_monitors.php | 30 +++--- web/ajax/alarm.php | 4 +- web/ajax/console.php | 16 ++-- web/ajax/control.php | 2 +- web/ajax/event.php | 2 +- web/ajax/log.php | 52 +++++------ web/ajax/status.php | 6 +- web/ajax/stream.php | 26 +++--- web/includes/Event.php | 1 + web/includes/Filter.php | 1 + web/includes/Frame.php | 1 + web/includes/Group.php | 1 + web/includes/Monitor.php | 1 + web/includes/MontageLayout.php | 7 +- web/includes/Server.php | 2 + web/includes/Storage.php | 2 + web/includes/actions/console.php | 4 +- web/includes/actions/control.php | 6 +- web/includes/actions/controlcap.php | 4 +- web/includes/actions/controlcaps.php | 5 +- web/includes/actions/device.php | 4 +- web/includes/actions/devices.php | 2 +- web/includes/actions/donate.php | 2 +- web/includes/actions/event.php | 2 +- web/includes/actions/eventdetail.php | 4 +- web/includes/actions/events.php | 4 +- web/includes/actions/filter.php | 8 +- web/includes/actions/function.php | 6 +- web/includes/actions/group.php | 2 +- web/includes/actions/groups.php | 4 +- web/includes/actions/monitor.php | 28 +++--- web/includes/actions/montage.php | 2 +- web/includes/actions/options.php | 2 +- web/includes/actions/privacy.php | 2 +- web/includes/actions/server.php | 4 +- web/includes/actions/settings.php | 4 +- web/includes/actions/state.php | 2 +- web/includes/actions/storage.php | 4 +- web/includes/actions/version.php | 2 +- web/includes/actions/zones.php | 2 +- web/includes/auth.php | 12 +-- web/includes/config.php.in | 2 +- web/includes/database.php | 30 +++--- web/includes/functions.php | 92 +++++++++---------- web/includes/logger.php | 1 + web/index.php | 1 + web/skins/classic/includes/functions.php | 6 +- web/skins/classic/views/_monitor_filters.php | 16 ++-- web/skins/classic/views/add_monitors.php | 10 +- web/skins/classic/views/console.php | 6 +- web/skins/classic/views/control.php | 2 +- web/skins/classic/views/cycle.php | 2 +- web/skins/classic/views/event.php | 2 +- web/skins/classic/views/events.php | 6 +- web/skins/classic/views/export.php | 2 +- web/skins/classic/views/filter.php | 4 +- web/skins/classic/views/frame.php | 6 +- web/skins/classic/views/frames.php | 4 +- web/skins/classic/views/group.php | 6 +- web/skins/classic/views/groups.php | 2 +- .../classic/views/js/montagereview.js.php | 8 +- web/skins/classic/views/monitor.php | 20 ++-- web/skins/classic/views/monitorprobe.php | 10 +- web/skins/classic/views/monitors.php | 6 +- web/skins/classic/views/montage.php | 8 +- web/skins/classic/views/montagereview.php | 2 +- web/skins/classic/views/onvifprobe.php | 14 +-- web/skins/classic/views/options.php | 4 +- .../classic/views/report_event_audit.php | 10 +- web/skins/classic/views/server.php | 7 +- web/skins/classic/views/storage.php | 2 +- web/skins/classic/views/timeline.php | 1 - web/skins/classic/views/watch.php | 2 +- web/skins/classic/views/zone.php | 2 +- web/views/archive.php | 10 +- web/views/image.php | 82 ++++++++--------- web/views/view_video.php | 14 +-- 77 files changed, 340 insertions(+), 337 deletions(-) diff --git a/web/ajax/add_monitors.php b/web/ajax/add_monitors.php index 69ce0332f..de24cdfac 100644 --- a/web/ajax/add_monitors.php +++ b/web/ajax/add_monitors.php @@ -1,6 +1,6 @@ set(array( 'StorageId' => 1, 'ServerId' => 'auto', @@ -19,11 +19,11 @@ function probe( &$url_bits ) { $cam_list_html = file_get_contents('http://'.$url_bits['host'].':5000/monitoring/'); if ( $cam_list_html ) { - Logger::Debug("Have content at port 5000/monitoring"); + ZM\Logger::Debug("Have content at port 5000/monitoring"); $matches_count = preg_match_all( '/([^<]+)<\/a>/', $cam_list_html, $cam_list ); - Logger::Debug(print_r($cam_list,true)); + ZM\Logger::Debug(print_r($cam_list,true)); } if ( $matches_count ) { for( $index = 0; $index < $matches_count; $index ++ ) { @@ -33,10 +33,10 @@ function probe( &$url_bits ) { if ( ! isset($new_stream['scheme'] ) ) $new_stream['scheme'] = 'http'; $available_streams[] = $new_stream; -Logger::Debug("Have new stream " . print_r($new_stream,true) ); +ZM\Logger::Debug("Have new stream " . print_r($new_stream,true) ); } } else { - Info('No matches'); + ZM\Info('No matches'); } if ( 0 ) { // No port given, do a port scan @@ -57,7 +57,7 @@ Info("Testing connection to " . $url_bits['host'].':'.$port); $new_stream['port'] = $port; } else { socket_close($socket); - Info("No connection to ".$url_bits['host'] . " on port $port"); + ZM\Info("No connection to ".$url_bits['host'] . " on port $port"); continue; } if ( $new_stream ) { @@ -65,7 +65,7 @@ Info("Testing connection to " . $url_bits['host'].':'.$port); $new_stream['scheme'] = 'http'; $url = unparse_url($new_stream, array('path'=>'/', 'query'=>'action=snapshot')); list($width, $height, $type, $attr) = getimagesize( $url ); - Info("Got $width x $height from $url"); + ZM\Info("Got $width x $height from $url"); $new_stream['Width'] = $width; $new_stream['Height'] = $height; @@ -93,9 +93,9 @@ Info("Testing connection to " . $url_bits['host'].':'.$port); foreach ( $available_streams as &$stream ) { # check for existence in db. $stream['url'] = unparse_url( $stream, array('path'=>'/','query'=>'action=stream') ); - $monitors = Monitor::find( array('Path'=>$stream['url']) ); + $monitors = ZM\Monitor::find( array('Path'=>$stream['url']) ); if ( count($monitors) ) { - Info("Found monitors matching " . $stream['url'] ); + ZM\Info("Found monitors matching " . $stream['url'] ); $stream['Monitor'] = $monitors[0]; if ( isset( $stream['Width'] ) and ( $stream['Monitor']->Width() != $stream['Width'] ) ) { $stream['Warning'] .= 'Monitor width ('.$stream['Monitor']->Width().') and stream width ('.$stream['Width'].") do not match!\n"; @@ -135,9 +135,9 @@ if ( canEdit( 'Monitors' ) ) { if ( 0 ) { // Shortcut test - $monitors = Monitor::find( array('Path'=>$_REQUEST['url']) ); + $monitors = ZM\Monitor::find( array('Path'=>$_REQUEST['url']) ); if ( count( $monitors ) ) { - Info("Monitor found for " . $_REQUEST['url']); + ZM\Info("Monitor found for " . $_REQUEST['url']); $url_bits['url'] = $_REQUEST['url']; $url_bits['Monitor'] = $monitors[0]; $available_stream[] = $url_bits; @@ -174,7 +174,7 @@ if ( 0 ) { $name = $data[0]; $url = $data[1]; $group = $data[2]; - Info("Have the following line data $name $url $group"); + ZM\Info("Have the following line data $name $url $group"); $url_bits = null; if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $url) ) { @@ -183,7 +183,7 @@ if ( 0 ) { $url_bits = parse_url( $url ); } if ( ! $url_bits ) { - Info("Bad url, skipping line $name $url $group"); + ZM\Info("Bad url, skipping line $name $url $group"); continue; } @@ -207,11 +207,11 @@ if ( 0 ) { } // end case import default: { - Warning("unknown action " . $_REQUEST['action'] ); + ZM\Warning("unknown action " . $_REQUEST['action'] ); } // end ddcase default } } else { - Warning("Cannot edit monitors" ); + ZM\Warning("Cannot edit monitors" ); } ajaxError( 'Unrecognised action or insufficient permissions' ); diff --git a/web/ajax/alarm.php b/web/ajax/alarm.php index 002f9f784..099bbf671 100644 --- a/web/ajax/alarm.php +++ b/web/ajax/alarm.php @@ -1,6 +1,6 @@ beginTransaction(); - $dbConn->exec( 'LOCK TABLES Monitors WRITE' ); + $dbConn->exec('LOCK TABLES Monitors WRITE'); for ( $i = 0; $i < count($monitor_ids); $i += 1 ) { $monitor_id = $monitor_ids[$i]; $monitor_id = preg_replace( '/^monitor_id-/', '', $monitor_id ); if ( ( ! $monitor_id ) or ! ( is_integer( $monitor_id ) or ctype_digit( $monitor_id ) ) ) { - Warning( "Got $monitor_id from " . $monitor_ids[$i] ); + Warning("Got $monitor_id from " . $monitor_ids[$i]); continue; } - dbQuery( 'UPDATE Monitors SET Sequence=? WHERE Id=?', array( $i, $monitor_id ) ); + dbQuery('UPDATE Monitors SET Sequence=? WHERE Id=?', array($i, $monitor_id)); } // end for each monitor_id $dbConn->commit(); $dbConn->exec('UNLOCK TABLES'); @@ -25,13 +24,12 @@ if ( canEdit( 'Monitors' ) ) { } // end case sort default: { - Warning("unknown action " . $_REQUEST['action'] ); + ZM\Warning('unknown action ' . $_REQUEST['action']); } // end ddcase default } } else { - Warning("Cannot edit monitors" ); + ZM\Warning('Cannot edit monitors'); } -ajaxError( 'Unrecognised action or insufficient permissions' ); - +ajaxError('Unrecognised action or insufficient permissions'); ?> diff --git a/web/ajax/control.php b/web/ajax/control.php index abdc8c8ef..ae7acac9e 100644 --- a/web/ajax/control.php +++ b/web/ajax/control.php @@ -8,7 +8,7 @@ if ( empty($_REQUEST['id']) ) if ( canView( 'Control', $_REQUEST['id'] ) ) { - $monitor = new Monitor( $_REQUEST['id'] ); + $monitor = new ZM\Monitor( $_REQUEST['id'] ); $ctrlCommand = buildControlCommand( $monitor ); diff --git a/web/ajax/event.php b/web/ajax/event.php index 4eed2e832..0756627b8 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -119,7 +119,7 @@ if ( canEdit( 'Events' ) ) { } case 'delete' : { - $Event = new Event( $_REQUEST['id'] ); + $Event = new ZM\Event( $_REQUEST['id'] ); if ( ! $Event->Id() ) { ajaxResponse( array( 'refreshEvent'=>false, 'refreshParent'=>true, 'message'=> 'Event not found.' ) ); } else { diff --git a/web/ajax/log.php b/web/ajax/log.php index 2a5aa039e..e8caff6bd 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -9,7 +9,7 @@ switch ( $_REQUEST['task'] ) { { // Silently ignore bogus requests if ( !empty($_POST['level']) && !empty($_POST['message']) ) { - logInit(array('id'=>'web_js')); + ZM\logInit(array('id'=>'web_js')); $string = $_POST['message']; @@ -21,9 +21,9 @@ switch ( $_REQUEST['task'] ) { $levels = array_flip(Logger::$codes); if ( !isset($levels[$_POST['level']]) ) - Panic("Unexpected logger level '".$_POST['level']."'"); + ZM\Panic("Unexpected logger level '".$_POST['level']."'"); $level = $levels[$_POST['level']]; - Logger::fetch()->logPrint($level, $string, $file, $line); + ZM\Logger::fetch()->logPrint($level, $string, $file, $line); } ajaxResponse(); break; @@ -33,7 +33,7 @@ switch ( $_REQUEST['task'] ) { if ( !canView('System') ) ajaxError('Insufficient permissions to view log entries'); - $servers = Server::find(); + $servers = ZM\Server::find(); $servers_by_Id = array(); # There is probably a better way to do this. foreach ( $servers as $server ) { @@ -46,7 +46,7 @@ switch ( $_REQUEST['task'] ) { $limit = 100; if ( isset($_REQUEST['limit']) ) { if ( ( !is_integer($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { - Error('Invalid value for limit ' . $_REQUEST['limit']); + ZM\Error('Invalid value for limit ' . $_REQUEST['limit']); } else { $limit = $_REQUEST['limit']; } @@ -54,7 +54,7 @@ switch ( $_REQUEST['task'] ) { $sortField = 'TimeKey'; if ( isset($_REQUEST['sortField']) ) { if ( !in_array($_REQUEST['sortField'], $filterFields) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) { - Error("Invalid sort field " . $_REQUEST['sortField']); + ZM\Error("Invalid sort field " . $_REQUEST['sortField']); } else { $sortField = $_REQUEST['sortField']; } @@ -76,7 +76,7 @@ switch ( $_REQUEST['task'] ) { foreach ( $filter as $field=>$value ) { if ( ! in_array($field, $filterFields) ) { - Error("$field is not in valid filter fields"); + ZM\Error("$field is not in valid filter fields"); continue; } if ( $field == 'Level' ){ @@ -105,8 +105,8 @@ switch ( $_REQUEST['task'] ) { $value = $log[$field]; if ( $field == 'Level' ) { - if ( $value <= Logger::INFO ) - $options[$field][$value] = Logger::$codes[$value]; + if ( $value <= ZM\Logger::INFO ) + $options[$field][$value] = ZM\Logger::$codes[$value]; else $options[$field][$value] = 'DB'.$value; } else if ( $field == 'ServerId' ) { @@ -146,14 +146,14 @@ switch ( $_REQUEST['task'] ) { $sortField = 'TimeKey'; if ( isset($_POST['sortField']) ) { if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) { - Error("Invalid sort field " . $_POST['sortField'] ); + ZM\Error("Invalid sort field " . $_POST['sortField'] ); } else { $sortField = $_POST['sortField']; } } $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc'; - $servers = Server::find(); + $servers = ZM\Server::find(); $servers_by_Id = array(); # There is probably a better way to do this. foreach ( $servers as $server ) { @@ -164,11 +164,11 @@ switch ( $_REQUEST['task'] ) { $where = array(); $values = array(); if ( $minTime ) { - Logger::Debug("MinTime: $minTime"); + ZM\Logger::Debug("MinTime: $minTime"); if ( preg_match('/(.+)(\.\d+)/', $minTime, $matches) ) { # This handles sub second precision $minTime = strtotime($matches[1]).$matches[2]; - Logger::Debug("MinTime: $minTime"); + ZM\Logger::Debug("MinTime: $minTime"); } else { $minTime = strtotime($minTime); } @@ -214,27 +214,27 @@ switch ( $_REQUEST['task'] ) { $exportExt = 'xml'; break; default : - Fatal("Unrecognised log export format '$format'"); + ZM\Fatal("Unrecognised log export format '$format'"); } $exportKey = substr(md5(rand()),0,8); $exportFile = "zm-log.$exportExt"; if ( ! file_exists(ZM_DIR_EXPORTS) ) { - Logger::Debug('Creating ' . ZM_DIR_EXPORTS); + ZM\Logger::Debug('Creating ' . ZM_DIR_EXPORTS); if ( ! mkdir(ZM_DIR_EXPORTS) ) { - Fatal("Can't create exports dir at '".ZM_DIR_EXPORTS."'"); + ZM\Fatal("Can't create exports dir at '".ZM_DIR_EXPORTS."'"); } } $exportPath = ZM_DIR_EXPORTS."/zm-log-$exportKey.$exportExt"; - Logger::Debug("Exporting to $exportPath"); + ZM\Logger::Debug("Exporting to $exportPath"); if ( !($exportFP = fopen($exportPath, 'w')) ) - Fatal("Unable to open log export file $exportPath"); + ZM\Fatal("Unable to open log export file $exportPath"); $logs = array(); foreach ( dbFetchAll($sql, NULL, $values) as $log ) { $log['DateTime'] = preg_replace('/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey']); $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; $logs[] = $log; } - Logger::Debug(count($logs)." lines being exported by $sql " . implode(',',$values)); + ZM\Logger::Debug(count($logs)." lines being exported by $sql " . implode(',',$values)); switch( $format ) { case 'text' : @@ -318,10 +318,10 @@ switch ( $_REQUEST['task'] ) { ' ); foreach ( $logs as $log ) { $classLevel = $log['Level']; - if ( $classLevel < Logger::FATAL ) - $classLevel = Logger::FATAL; - elseif ( $classLevel > Logger::DEBUG ) - $classLevel = Logger::DEBUG; + if ( $classLevel < ZM\Logger::FATAL ) + $classLevel = ZM\Logger::FATAL; + elseif ( $classLevel > ZM\Logger::DEBUG ) + $classLevel = ZM\Logger::DEBUG; $logClass = 'log-'.strtolower(Logger::$codes[$classLevel]); fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); } @@ -384,10 +384,10 @@ switch ( $_REQUEST['task'] ) { ajaxError('Insufficient permissions to download logs'); if ( empty($_REQUEST['key']) ) - Fatal('No log export key given'); + ZM\Fatal('No log export key given'); $exportKey = $_REQUEST['key']; if ( empty($_REQUEST['format']) ) - Fatal('No log export format given'); + ZM\Fatal('No log export format given'); $format = $_REQUEST['format']; switch( $format ) { @@ -404,7 +404,7 @@ switch ( $_REQUEST['task'] ) { $exportExt = 'xml'; break; default : - Fatal("Unrecognised log export format '$format'"); + ZM\Fatal("Unrecognised log export format '$format'"); } $exportFile = "zm-log.$exportExt"; diff --git a/web/ajax/status.php b/web/ajax/status.php index 7692b2e67..f95f16c8c 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -284,7 +284,7 @@ function collectData() { if ( in_array($matches[1], $fieldSql) ) { $sql .= $matches[1]; } else { - Error('Sort field ' . $matches[1] . ' not in SQL Fields'); + ZM\Error('Sort field ' . $matches[1] . ' not in SQL Fields'); } if ( count($matches) > 2 ) { $sql .= ' '.strtoupper($matches[2]); @@ -292,7 +292,7 @@ function collectData() { $sql .= ' '.strtoupper($matches[3]); } } else { - Error("Sort field didn't match regexp $sort_field"); + ZM\Error("Sort field didn't match regexp $sort_field"); } } # end foreach sort field } # end if has sort @@ -323,7 +323,7 @@ function collectData() { } } } - #Logger::Debug(print_r($data, true)); + #ZM\Logger::Debug(print_r($data, true)); return $data; } diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 44aaec8e6..b60cf32f5 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -20,7 +20,7 @@ if ( sem_acquire($semaphore,1) !== false ) { $localSocketFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'w.sock'; if ( file_exists( $localSocketFile ) ) { - Warning("sock file $localSocketFile already exists?! Is someone else talking to zms?"); + ZM\Warning("sock file $localSocketFile already exists?! Is someone else talking to zms?"); // They could be. We can maybe have concurrent requests from a browser. } if ( ! socket_bind( $socket, $localSocketFile ) ) { @@ -29,23 +29,23 @@ if ( sem_acquire($semaphore,1) !== false ) { switch ( $_REQUEST['command'] ) { case CMD_VARPLAY : - Logger::Debug( 'Varplaying to '.$_REQUEST['rate'] ); + ZM\Logger::Debug( 'Varplaying to '.$_REQUEST['rate'] ); $msg = pack( 'lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768 ); break; case CMD_ZOOMIN : - Logger::Debug( 'Zooming to '.$_REQUEST['x'].",".$_REQUEST['y'] ); + ZM\Logger::Debug( 'Zooming to '.$_REQUEST['x'].",".$_REQUEST['y'] ); $msg = pack( 'lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] ); break; case CMD_PAN : - Logger::Debug( 'Panning to '.$_REQUEST['x'].",".$_REQUEST['y'] ); + ZM\Logger::Debug( 'Panning to '.$_REQUEST['x'].",".$_REQUEST['y'] ); $msg = pack( 'lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] ); break; case CMD_SCALE : - Logger::Debug( 'Scaling to '.$_REQUEST['scale'] ); + ZM\Logger::Debug( 'Scaling to '.$_REQUEST['scale'] ); $msg = pack( 'lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale'] ); break; case CMD_SEEK : - Logger::Debug( 'Seeking to '.$_REQUEST['offset'] ); + ZM\Logger::Debug( 'Seeking to '.$_REQUEST['offset'] ); $msg = pack( 'lcN', MSG_CMD, $_REQUEST['command'], $_REQUEST['offset'] ); break; default : @@ -81,18 +81,18 @@ if ( sem_acquire($semaphore,1) !== false ) { $numSockets = socket_select( $rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000 ); if ( $numSockets === false ) { - Error('socket_select failed: ' . socket_strerror(socket_last_error()) ); + ZM\Error('socket_select failed: ' . socket_strerror(socket_last_error()) ); ajaxError( 'socket_select failed: '.socket_strerror(socket_last_error()) ); } else if ( $numSockets < 0 ) { - Error( "Socket closed $remSockFile" ); + ZM\Error( "Socket closed $remSockFile" ); ajaxError( "Socket closed $remSockFile" ); } else if ( $numSockets == 0 ) { - Error( "Timed out waiting for msg $remSockFile" ); + ZM\Error( "Timed out waiting for msg $remSockFile" ); socket_Set_nonblock($socket); #ajaxError( "Timed out waiting for msg $remSockFile" ); } else if ( $numSockets > 0 ) { if ( count($rSockets) != 1 ) { - Error( 'Bogus return from select, '.count($rSockets).' sockets available' ); + ZM\Error( 'Bogus return from select, '.count($rSockets).' sockets available' ); ajaxError( 'Bogus return from select, '.count($rSockets).' sockets available' ); } } @@ -122,9 +122,9 @@ if ( sem_acquire($semaphore,1) !== false ) { case MSG_DATA_WATCH : { $data = unpack( "ltype/imonitor/istate/dfps/ilevel/irate/ddelay/izoom/Cdelayed/Cpaused/Cenabled/Cforced", $msg ); - Logger::Debug("FPS: " . $data['fps'] ); + ZM\Logger::Debug("FPS: " . $data['fps'] ); $data['fps'] = round( $data['fps'], 2 ); - Logger::Debug("FPS: " . $data['fps'] ); + ZM\Logger::Debug("FPS: " . $data['fps'] ); $data['rate'] /= RATE_BASE; $data['delay'] = round( $data['delay'], 2 ); $data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 ); @@ -161,7 +161,7 @@ if ( sem_acquire($semaphore,1) !== false ) { } sem_release($semaphore); } else { - Logger::Debug("Couldn't get semaphore"); + ZM\Logger::Debug("Couldn't get semaphore"); ajaxResponse( array() ); } diff --git a/web/includes/Event.php b/web/includes/Event.php index a4f389aca..51995ac19 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -1,4 +1,5 @@ fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout'); - foreach ( $results as $row => $obj ) { - $filters[] = $obj; + $results = $result->fetchALL(); + foreach ( $results as $row ) { + $filters[] = new MontageLayout($row); } } return $filters; diff --git a/web/includes/Server.php b/web/includes/Server.php index ea633c4be..96d07e9c1 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -1,8 +1,10 @@ null, diff --git a/web/includes/Storage.php b/web/includes/Storage.php index a7372b15a..67264f298 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -1,5 +1,7 @@ delete(); } // end if monitor found in db } // end if canedit this monitor diff --git a/web/includes/actions/control.php b/web/includes/actions/control.php index d3a75a751..36f6b14fb 100644 --- a/web/includes/actions/control.php +++ b/web/includes/actions/control.php @@ -20,11 +20,11 @@ // Monitor control actions, require a monitor id and control view permissions for that monitor if ( empty($_REQUEST['mid']) ) { - Warning("Settings requires a monitor id"); + ZM\Warning('Settings requires a monitor id'); return; } if ( ! canView('Control', $_REQUEST['mid']) ) { - Warning("Settings requires the Control permission"); + ZM\Warning('Settings requires the Control permission'); return; } @@ -32,7 +32,7 @@ require_once('control_functions.php'); require_once('Monitor.php'); $mid = validInt($_REQUEST['mid']); if ( $action == 'control' ) { - $monitor = new Monitor($mid); + $monitor = new ZM\Monitor($mid); $ctrlCommand = buildControlCommand($monitor); sendControlCommand($monitor->Id(), $ctrlCommand); diff --git a/web/includes/actions/controlcap.php b/web/includes/actions/controlcap.php index 71b59e1b6..eec3ffd8b 100644 --- a/web/includes/actions/controlcap.php +++ b/web/includes/actions/controlcap.php @@ -20,13 +20,13 @@ if ( !canEdit('Control') ) { - Warning("Need Control permissions to edit control capabilities"); + ZM\Warning('Need Control permissions to edit control capabilities'); return; } // end if !canEdit Controls if ( $action == 'controlcap' ) { require_once('includes/Control.php'); - $Control = new Control( !empty($_REQUEST['cid']) ? $_REQUEST['cid'] : null ); + $Control = new ZM\Control( !empty($_REQUEST['cid']) ? $_REQUEST['cid'] : null ); //$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns ); $Control->save($_REQUEST['newControl']); diff --git a/web/includes/actions/controlcaps.php b/web/includes/actions/controlcaps.php index f67a37dad..3e5310d19 100644 --- a/web/includes/actions/controlcaps.php +++ b/web/includes/actions/controlcaps.php @@ -20,16 +20,15 @@ if ( !canEdit('Control') ) { - Warning("Need Control permissions to edit control capabilities"); + ZM\Warning('Need Control permissions to edit control capabilities'); return; } // end if !canEdit Controls -} if ( $action == 'delete' ) { if ( isset($_REQUEST['markCids']) ) { foreach( $_REQUEST['markCids'] as $markCid ) { - dbQuery('DELETE FROM Controls WHERE Id = ?', array($markCid)); dbQuery('UPDATE Monitors SET Controllable = 0, ControlId = 0 WHERE ControlId = ?', array($markCid)); + dbQuery('DELETE FROM Controls WHERE Id = ?', array($markCid)); $refreshParent = true; } } diff --git a/web/includes/actions/device.php b/web/includes/actions/device.php index a9d1f9e5a..c1a882d89 100644 --- a/web/includes/actions/device.php +++ b/web/includes/actions/device.php @@ -20,7 +20,7 @@ // Device view actions if ( !canEdit('Devices') ) { - Warning("No devices permission in editing device"); + ZM\Warning('No devices permission in editing device'); return; } // end if !canEdit(Devices) @@ -39,7 +39,7 @@ if ( $action == 'device' ) { $view = 'none'; } } else { - Error("Unknown action in device"); + ZM\Error('Unknown action in device'); } // end if action ?> diff --git a/web/includes/actions/devices.php b/web/includes/actions/devices.php index 4cb5d43a3..01c562370 100644 --- a/web/includes/actions/devices.php +++ b/web/includes/actions/devices.php @@ -20,7 +20,7 @@ // Device view actions if ( !canEdit('Devices') ) { - Warning("No devices permission in editing device"); + ZM\Warning('No devices permission in editing device'); return; } // end if !canEdit(Devices) diff --git a/web/includes/actions/donate.php b/web/includes/actions/donate.php index 74361c4e5..156491ede 100644 --- a/web/includes/actions/donate.php +++ b/web/includes/actions/donate.php @@ -19,7 +19,7 @@ // if ( !canEdit('System') ) { - Warning("Need System permissions to update donation"); + ZM\Warning('Need System permissions to update donation'); return; } diff --git a/web/includes/actions/event.php b/web/includes/actions/event.php index 89a2694c8..a3c6d56c3 100644 --- a/web/includes/actions/event.php +++ b/web/includes/actions/event.php @@ -20,7 +20,7 @@ // If there is an action on an event, then we must have an id. if ( !empty($_REQUEST['eid']) ) { - Warning("No eid in action on event view"); + ZM\Warning('No eid in action on event view'); return; } diff --git a/web/includes/actions/eventdetail.php b/web/includes/actions/eventdetail.php index 561c2cb78..20bd084ee 100644 --- a/web/includes/actions/eventdetail.php +++ b/web/includes/actions/eventdetail.php @@ -19,13 +19,13 @@ // if ( !isset($_REQUEST['markEids']) ) { - Warning('Events actions require eids'); + ZM\Warning('Events actions require eids'); return; } // Event scope actions, view permissions only required if ( !canEdit('Events') ) { - Warning("Events actions require Edit permissions"); + ZM\Warning('Events actions require Edit permissions'); return; } // end if ! canEdit(Events) diff --git a/web/includes/actions/events.php b/web/includes/actions/events.php index 10642f329..d7e4c18d8 100644 --- a/web/includes/actions/events.php +++ b/web/includes/actions/events.php @@ -19,13 +19,13 @@ // if ( !isset($_REQUEST['markEids']) ) { - Warning('Events actions require eids'); + ZM\Warning('Events actions require eids'); return; } // Event scope actions, view permissions only required if ( !canEdit('Events') ) { - Warning("Events actions require Edit permissions"); + ZM\Warning('Events actions require Edit permissions'); return; } // end if ! canEdit(Events) diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php index c15f36c65..a89938697 100644 --- a/web/includes/actions/filter.php +++ b/web/includes/actions/filter.php @@ -20,7 +20,7 @@ // Event scope actions, view permissions only required if ( !canView('Events') ) { - Warning('You do not have permission to view Events.'); + ZM\Warning('You do not have permission to view Events.'); return; } @@ -32,7 +32,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } else if ( canEdit('Events') ) { require_once('includes/Filter.php'); - $filter = new Filter($_REQUEST['Id']); + $filter = new ZM\Filter($_REQUEST['Id']); if ( $action == 'delete' ) { if ( !empty($_REQUEST['Id']) ) { @@ -42,7 +42,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { $filter->delete(); } else { - Error("No filter id passed when deleting"); + ZM\Error("No filter id passed when deleting"); } } else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) { @@ -98,7 +98,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { ) { $filter->control($_REQUEST['command'], $_REQUEST['ServerId']); } else { - Error('Invalid command for filter ('.$_REQUEST['command'].')'); + ZM\Error('Invalid command for filter ('.$_REQUEST['command'].')'); } } // end if save or execute } // end if canEdit(Events) diff --git a/web/includes/actions/function.php b/web/includes/actions/function.php index 5fca0d8a1..f60b98fda 100644 --- a/web/includes/actions/function.php +++ b/web/includes/actions/function.php @@ -21,12 +21,12 @@ // Monitor edit actions, require a monitor id and edit permissions for that monitor if ( empty($_REQUEST['mid']) ) { - Error("Must specify mid"); + ZM\Error('Must specify mid'); return; } $mid = validInt($_REQUEST['mid']); if ( !canEdit('Monitors', $mid) ) { - Error("You do not have permission to edit monitor $mid"); + ZM\Error("You do not have permission to edit monitor $mid"); return; } @@ -52,7 +52,7 @@ if ( $action == 'function' ) { } $refreshParent = true; } else { - Logger::Debug("No change to function, not doing anything."); + ZM\Logger::Debug('No change to function, not doing anything.'); } } // end if action $view = 'none'; diff --git a/web/includes/actions/group.php b/web/includes/actions/group.php index 36a3f8faa..ec4f28969 100644 --- a/web/includes/actions/group.php +++ b/web/includes/actions/group.php @@ -22,7 +22,7 @@ # Should probably verify that each monitor id is a valid monitor, that we have access to. # However at the moment, you have to have System permissions to do this if ( ! canEdit('Groups') ) { - Warning("Need group edit permissions to edit groups"); + ZM\Warning('Need group edit permissions to edit groups'); return; } diff --git a/web/includes/actions/groups.php b/web/includes/actions/groups.php index 22d138240..8e4522187 100644 --- a/web/includes/actions/groups.php +++ b/web/includes/actions/groups.php @@ -33,13 +33,13 @@ if ( ($action == 'setgroup') && canView('Groups')) { # Should probably verify that each monitor id is a valid monitor, that we have access to. # However at the moment, you have to have System permissions to do this if ( ! canEdit('Groups') ) { - Warning("Need group edit permissions to edit groups"); + ZM\Warning('Need group edit permissions to edit groups'); return; } if ( $action == 'delete' ) { if ( !empty($_REQUEST['gid']) ) { - foreach ( Group::find(array('Id'=>$_REQUEST['gid'])) as $Group ) { + foreach ( ZM\Group::find(array('Id'=>$_REQUEST['gid'])) as $Group ) { $Group->delete(); } } diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 2e73e4184..815100e4e 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -25,10 +25,10 @@ if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) { foreach ( $_REQUEST['mids'] as $mid ) { $mid = ValidInt($mid); if ( ! canEdit('Monitors', $mid) ) { - Warning("Cannot edit monitor $mid"); + ZM\Warning("Cannot edit monitor $mid"); continue; } - $Monitor = new Monitor($mid); + $Monitor = new ZM\Monitor($mid); if ( $Monitor->Type() != 'WebSite' ) { $Monitor->zmaControl('stop'); $Monitor->zmcControl('stop'); @@ -47,7 +47,7 @@ if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) { // Monitor edit actions, monitor id derived, require edit permissions for that monitor if ( ! canEdit('Monitors') ) { - Warning("Monitor actions require Monitors Permissions"); + ZM\Warning("Monitor actions require Monitors Permissions"); return; } @@ -68,7 +68,7 @@ if ( $action == 'monitor' ) { $x10Monitor = array(); } } - $Monitor = new Monitor($monitor); + $Monitor = new ZM\Monitor($monitor); // Define a field type for anything that's not simple text equivalent $types = array( @@ -86,10 +86,10 @@ if ( $action == 'monitor' ) { if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) { $_REQUEST['newMonitor']['ServerId'] = dbFetchOne( 'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id'); - Logger::Debug('Auto selecting server: Got ' . $_REQUEST['newMonitor']['ServerId'] ); + ZM\Logger::Debug('Auto selecting server: Got ' . $_REQUEST['newMonitor']['ServerId'] ); if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) { $_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID; - Logger::Debug('Auto selecting server to ' . ZM_SERVER_ID); + ZM\Logger::Debug('Auto selecting server to ' . ZM_SERVER_ID); } } @@ -107,12 +107,12 @@ if ( $action == 'monitor' ) { dbQuery('UPDATE Monitors SET '.implode(', ', $changes).' WHERE Id=?', array($mid)); // Groups will be added below if ( isset($changes['Name']) or isset($changes['StorageId']) ) { - $OldStorage = new Storage($monitor['StorageId']); + $OldStorage = new ZM\Storage($monitor['StorageId']); $saferOldName = basename($monitor['Name']); if ( file_exists($OldStorage->Path().'/'.$saferOldName) ) unlink($OldStorage->Path().'/'.$saferOldName); - $NewStorage = new Storage($_REQUEST['newMonitor']['StorageId']); + $NewStorage = new ZM\Storage($_REQUEST['newMonitor']['StorageId']); if ( ! file_exists($NewStorage->Path().'/'.$mid) ) mkdir($NewStorage->Path().'/'.$mid, 0755); $saferNewName = basename($_REQUEST['newMonitor']['Name']); @@ -164,24 +164,24 @@ if ( $action == 'monitor' ) { $zoneArea = $_REQUEST['newMonitor']['Width'] * $_REQUEST['newMonitor']['Height']; dbQuery("INSERT INTO Zones SET MonitorId = ?, Name = 'All', Type = 'Active', Units = 'Percent', NumCoords = 4, Coords = ?, Area=?, AlarmRGB = 0xff0000, CheckMethod = 'Blobs', MinPixelThreshold = 25, MinAlarmPixels=?, MaxAlarmPixels=?, FilterX = 3, FilterY = 3, MinFilterPixels=?, MaxFilterPixels=?, MinBlobPixels=?, MinBlobs = 1", array( $mid, sprintf( "%d,%d %d,%d %d,%d %d,%d", 0, 0, $_REQUEST['newMonitor']['Width']-1, 0, $_REQUEST['newMonitor']['Width']-1, $_REQUEST['newMonitor']['Height']-1, 0, $_REQUEST['newMonitor']['Height']-1 ), $zoneArea, intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*2)/100) ) ); //$view = 'none'; - $Storage = new Storage($_REQUEST['newMonitor']['StorageId']); + $Storage = new ZM\Storage($_REQUEST['newMonitor']['StorageId']); mkdir($Storage->Path().'/'.$mid, 0755); $saferName = basename($_REQUEST['newMonitor']['Name']); symlink($mid, $Storage->Path().'/'.$saferName); } else { - Error('Error saving new Monitor.'); + ZM\Error('Error saving new Monitor.'); $error_message = dbError($sql); return; } } else { - Error('Users with Monitors restrictions cannot create new monitors.'); + ZM\Error('Users with Monitors restrictions cannot create new monitors.'); return; } $restart = true; } else { - Logger::Debug('No action due to no changes to Monitor'); + ZM\Logger::Debug('No action due to no changes to Monitor'); } # end if count(changes) if ( @@ -220,7 +220,7 @@ if ( $action == 'monitor' ) { if ( $restart ) { - $new_monitor = new Monitor($mid); + $new_monitor = new ZM\Monitor($mid); //fixDevices(); if ( $new_monitor->Type() != 'WebSite' ) { @@ -238,6 +238,6 @@ if ( $action == 'monitor' ) { } // end if restart $view = 'none'; } else { - Warning("Unknown action $action in Monitor"); + ZM\Warning("Unknown action $action in Monitor"); } // end if action == Delete ?> diff --git a/web/includes/actions/montage.php b/web/includes/actions/montage.php index 3040fd83a..7ab105d0c 100644 --- a/web/includes/actions/montage.php +++ b/web/includes/actions/montage.php @@ -22,7 +22,7 @@ if ( isset($_REQUEST['object']) ) { if ( $_REQUEST['object'] == 'MontageLayout' ) { // System edit actions if ( ! canEdit('System') ) { - Warning("Need System permissions to edit layouts"); + ZM\Warning('Need System permissions to edit layouts'); return; } require_once('includes/MontageLayout.php'); diff --git a/web/includes/actions/options.php b/web/includes/actions/options.php index d7853ec9e..0c80bacf0 100644 --- a/web/includes/actions/options.php +++ b/web/includes/actions/options.php @@ -20,7 +20,7 @@ // System edit actions if ( !canEdit('System') ) { - Warning("Must have System permissions to perform options actions"); + ZM\Warning('Must have System permissions to perform options actions'); return; } diff --git a/web/includes/actions/privacy.php b/web/includes/actions/privacy.php index 99bbd7150..5712d5b40 100644 --- a/web/includes/actions/privacy.php +++ b/web/includes/actions/privacy.php @@ -19,7 +19,7 @@ // if ( !canEdit('System') ) { - Warning("Need System permissions to update privacy"); + ZM\Warning('Need System permissions to update privacy'); return; } diff --git a/web/includes/actions/server.php b/web/includes/actions/server.php index d991fd228..1ffe4933d 100644 --- a/web/includes/actions/server.php +++ b/web/includes/actions/server.php @@ -20,7 +20,7 @@ // System edit actions if ( ! canEdit('System') ) { - Warning("Need System permissions to add servers"); + ZM\Warning('Need System permissions to add servers'); return; } @@ -48,6 +48,6 @@ if ( $action == 'Save' ) { } $view = 'none'; } else { - Error("Unknown action $action in saving Server"); + ZM\Error("Unknown action $action in saving Server"); } ?> diff --git a/web/includes/actions/settings.php b/web/includes/actions/settings.php index 872dae95e..25c4f76d4 100644 --- a/web/includes/actions/settings.php +++ b/web/includes/actions/settings.php @@ -21,11 +21,11 @@ // Monitor control actions, require a monitor id and control view permissions for that monitor if ( empty($_REQUEST['mid']) ) { - Warning("Settings requires a monitor id"); + ZM\Warning('Settings requires a monitor id'); return; } if ( ! canView('Control', $_REQUEST['mid']) ) { - Warning("Settings requires the Control permission"); + ZM\Warning('Settings requires the Control permission'); return; } diff --git a/web/includes/actions/state.php b/web/includes/actions/state.php index 9cb5eb8c9..9799cdec3 100644 --- a/web/includes/actions/state.php +++ b/web/includes/actions/state.php @@ -20,7 +20,7 @@ // System edit actions if ( !canEdit('System') ) { - Warning('Need System Permission to edit states'); + ZM\Warning('Need System Permission to edit states'); return; } if ( $action == 'state' ) { diff --git a/web/includes/actions/storage.php b/web/includes/actions/storage.php index 94b76bae7..f60c8227d 100644 --- a/web/includes/actions/storage.php +++ b/web/includes/actions/storage.php @@ -20,7 +20,7 @@ // System edit actions if ( ! canEdit('System') ) { - Warning("Need System permission to edit Storage"); + ZM\Warning('Need System permission to edit Storage'); return; } @@ -43,7 +43,7 @@ if ( $action == 'Save' ) { } $view = 'none'; } else { - Error("Unknown action $action in saving Storage"); + ZM\Error("Unknown action $action in saving Storage"); } ?> diff --git a/web/includes/actions/version.php b/web/includes/actions/version.php index 0e89b2457..fde85427f 100644 --- a/web/includes/actions/version.php +++ b/web/includes/actions/version.php @@ -20,7 +20,7 @@ // System edit actions if ( !canEdit('System') ) { - Warning("Need System permissions to update version"); + ZM\Warning('Need System permissions to update version'); return; } if ( $action == 'version' && isset($_REQUEST['option']) ) { diff --git a/web/includes/actions/zones.php b/web/includes/actions/zones.php index f7ee15c9d..babb4fa7b 100644 --- a/web/includes/actions/zones.php +++ b/web/includes/actions/zones.php @@ -20,7 +20,7 @@ if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) { $mid = validInt($_REQUEST['mid']); - $monitor = new Monitor($mid); + $monitor = new ZM\Monitor($mid); if ( $action == 'delete' ) { if ( isset($_REQUEST['markZids']) ) { diff --git a/web/includes/auth.php b/web/includes/auth.php index c74c13b80..9f12a2b8f 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -87,7 +87,7 @@ function userLogin($username='', $password='', $passwordHashed=false) { } $_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking if ( $dbUser = dbFetchOne($sql, NULL, $sql_values) ) { - Info("Login successful for user \"$username\""); + ZM\Info("Login successful for user \"$username\""); $_SESSION['user'] = $user = $dbUser; unset($_SESSION['loginFailed']); if ( ZM_AUTH_TYPE == 'builtin' ) { @@ -95,7 +95,7 @@ function userLogin($username='', $password='', $passwordHashed=false) { } session_regenerate_id(); } else { - Warning("Login denied for user \"$username\""); + ZM\Warning("Login denied for user \"$username\""); $_SESSION['loginFailed'] = true; unset($user); } @@ -106,7 +106,7 @@ function userLogin($username='', $password='', $passwordHashed=false) { function userLogout() { global $user; - Info('User "'.$user['Username'].'" logged out'); + ZM\Info('User "'.$user['Username'].'" logged out'); session_start(); unset($_SESSION['user']); unset($user); @@ -119,7 +119,7 @@ function getAuthUser($auth) { if ( ZM_AUTH_HASH_IPS ) { $remoteAddr = $_SERVER['REMOTE_ADDR']; if ( !$remoteAddr ) { - Error("Can't determine remote address for authentication, using empty string"); + ZM\Error("Can't determine remote address for authentication, using empty string"); $remoteAddr = ''; } } @@ -145,7 +145,7 @@ function getAuthUser($auth) { } // end foreach hour } // end foreach user } // end if using auth hash - Error("Unable to authenticate user from auth hash '$auth'"); + ZM\Error("Unable to authenticate user from auth hash '$auth'"); return false; } // end getAuthUser($auth) @@ -213,7 +213,7 @@ function is_session_started() { return session_id() === '' ? FALSE : TRUE; } } else { - Warning("php_sapi_name === 'cli'"); + ZM\Warning("php_sapi_name === 'cli'"); } return FALSE; } diff --git a/web/includes/config.php.in b/web/includes/config.php.in index bf4b24e0b..01382ad37 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -138,7 +138,7 @@ define( 'MYSQL_FMT_DATETIME_SHORT', '%y/%m/%d %H:%i:%S' ); // MySQL date_format require_once( 'database.php' ); require_once( 'logger.php' ); loadConfig(); -Logger::fetch()->initialise(); +ZM\Logger::fetch()->initialise(); $GLOBALS['defaultUser'] = array( 'Username' => 'admin', diff --git a/web/includes/database.php b/web/includes/database.php index 95fabee11..b567f6c6d 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -93,7 +93,7 @@ function dbLog( $sql, $update=false ) { global $dbLogLevel; $noExecute = $update && ($dbLogLevel >= DB_LOG_DEBUG); if ( $dbLogLevel > DB_LOG_OFF ) - Logger::Debug( "SQL-LOG: $sql".($noExecute?" (not executed)":"") ); + ZM\Logger::Debug( "SQL-LOG: $sql".($noExecute?" (not executed)":"") ); return( $noExecute ); } @@ -104,7 +104,7 @@ function dbError( $sql ) { return ''; $message = "SQL-ERR '".implode("\n",$dbConn->errorInfo())."', statement was '".$sql."'"; - Error($message); + ZM\Error($message); return $message; } @@ -130,32 +130,32 @@ function dbQuery( $sql, $params=NULL ) { try { if ( isset($params) ) { if ( ! $result = $dbConn->prepare( $sql ) ) { - Error("SQL: Error preparing $sql: " . $pdo->errorInfo); + ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo); return NULL; } if ( ! $result->execute( $params ) ) { - Error("SQL: Error executing $sql: " . implode(',', $result->errorInfo() ) ); + ZM\Error("SQL: Error executing $sql: " . implode(',', $result->errorInfo() ) ); return NULL; } } else { if ( defined('ZM_DB_DEBUG') ) { - Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):'') ); + ZM\Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):'') ); } $result = $dbConn->query($sql); if ( ! $result ) { - Error("SQL: Error preparing $sql: " . $pdo->errorInfo); + ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo); return NULL; } } if ( defined('ZM_DB_DEBUG') ) { if ( $params ) - Logger::Debug("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() ); + ZM\Logger::Debug("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() ); else - Logger::Debug("SQL: $sql: rows:" . $result->rowCount() ); + ZM\Logger::Debug("SQL: $sql: rows:" . $result->rowCount() ); } } catch(PDOException $e) { - Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . ($params?implode(',',$params):'') ); + ZM\Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . ($params?implode(',',$params):'') ); return NULL; } return $result; @@ -164,7 +164,7 @@ function dbQuery( $sql, $params=NULL ) { function dbFetchOne( $sql, $col=false, $params=NULL ) { $result = dbQuery( $sql, $params ); if ( ! $result ) { - Error( "SQL-ERR dbFetchOne no result, statement was '".$sql."'" . ( $params ? 'params: ' . join(',',$params) : '' ) ); + ZM\Error( "SQL-ERR dbFetchOne no result, statement was '".$sql."'" . ( $params ? 'params: ' . join(',',$params) : '' ) ); return false; } if ( ! $result->rowCount() ) { @@ -175,7 +175,7 @@ function dbFetchOne( $sql, $col=false, $params=NULL ) { if ( $result && $dbRow = $result->fetch(PDO::FETCH_ASSOC) ) { if ( $col ) { if ( ! array_key_exists($col, $dbRow) ) { - Warning("$col does not exist in the returned row " . print_r($dbRow, true)); + ZM\Warning("$col does not exist in the returned row " . print_r($dbRow, true)); } return $dbRow[$col]; } @@ -187,7 +187,7 @@ function dbFetchOne( $sql, $col=false, $params=NULL ) { function dbFetchAll( $sql, $col=false, $params=NULL ) { $result = dbQuery( $sql, $params ); if ( ! $result ) { - Error( "SQL-ERR dbFetchAll no result, statement was '".$sql."'" . ( $params ? 'params: ' .join(',', $params) : '' ) ); + ZM\Error( "SQL-ERR dbFetchAll no result, statement was '".$sql."'" . ( $params ? 'params: ' .join(',', $params) : '' ) ); return false; } @@ -294,7 +294,7 @@ function getTableDescription( $table, $asString=1 ) { //$desc['minLength'] = -128; break; default : - Error( "Unexpected text qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); + ZM\Error( "Unexpected text qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); break; } } elseif ( preg_match( "/^(enum|set)\((.*)\)$/", $row['Type'], $matches ) ) { @@ -326,7 +326,7 @@ function getTableDescription( $table, $asString=1 ) { //$desc['maxValue'] = 127; break; default : - Error( "Unexpected integer qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); + ZM\Error( "Unexpected integer qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); break; } if ( !empty($matches[1]) ) @@ -361,7 +361,7 @@ function getTableDescription( $table, $asString=1 ) { break; } } else { - Error( "Can't parse database type '".$row['Type']."' found for field '".$row['Field']."' in table '".$table."'" ); + ZM\Error( "Can't parse database type '".$row['Type']."' found for field '".$row['Field']."' in table '".$table."'" ); } if ( $asString ) diff --git a/web/includes/functions.php b/web/includes/functions.php index 0a224358a..29247e377 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -90,12 +90,12 @@ function CORSHeaders() { # The following is left for future reference/use. $valid = false; - $Servers = Server::find(); + $Servers = ZM\Server::find(); if ( sizeof($Servers) < 1 ) { # Only need CORSHeaders in the event that there are multiple servers in use. # ICON: Might not be true. multi-port? if ( ZM_MIN_STREAMING_PORT ) { - Logger::Debug("Setting default Access-Control-Allow-Origin from " . $_SERVER['HTTP_ORIGIN']); + ZM\Logger::Debug('Setting default Access-Control-Allow-Origin from ' . $_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Headers: x-requested-with,x-request'); } @@ -108,14 +108,14 @@ function CORSHeaders() { preg_match('/^(https?:\/\/)?'.preg_quote($Server->Name(),'/').'/i', $_SERVER['HTTP_ORIGIN']) ) { $valid = true; - Logger::Debug("Setting Access-Control-Allow-Origin from " . $_SERVER['HTTP_ORIGIN']); + ZM\Logger::Debug("Setting Access-Control-Allow-Origin from " . $_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Headers: x-requested-with,x-request'); break; } } if ( !$valid ) { - Warning($_SERVER['HTTP_ORIGIN'] . ' is not found in servers list.'); + ZM\Warning($_SERVER['HTTP_ORIGIN'] . ' is not found in servers list.'); } } } @@ -409,7 +409,7 @@ function getZmuCommand( $args ) { } function getEventDefaultVideoPath( $event ) { - $Event = new Event( $event ); + $Event = new ZM\Event( $event ); return $Event->getStreamSrc( array( 'mode'=>'mpeg', 'format'=>'h264' ) ); } @@ -424,15 +424,15 @@ function deletePath( $path ) { function deleteEvent( $event ) { if ( empty($event) ) { - Error( 'Empty event passed to deleteEvent.'); + ZM\Error('Empty event passed to deleteEvent.'); return; } if ( gettype($event) != 'array' ) { # $event could be an eid, so turn it into an event hash - $event = new Event( $event ); + $event = new ZM\Event( $event ); } else { -Logger::Debug("Event type: " . gettype($event)); +ZM\Logger::Debug("Event type: " . gettype($event)); } global $user; @@ -527,7 +527,7 @@ function htmlOptions($contents, $values) { if ( isset($option['disabled']) ) { $disabled = $option['disabled']; - Error("Setting to disabled"); + ZM\Error("Setting to disabled"); } } else if ( is_object($option) ) { $text = $option->Name(); @@ -556,7 +556,7 @@ function buildSelect( $name, $contents, $behaviours=false ) { elseif ( isset($_REQUEST[$arr]) ) $value = $_REQUEST[$arr]; if ( !preg_match_all( '/\[\s*[\'"]?(\w+)["\']?\s*\]/', $matches[2], $matches ) ) { - Fatal( "Can't parse selector '$name'" ); + ZM\Fatal( "Can't parse selector '$name'" ); } for ( $i = 0; $i < count($matches[1]); $i++ ) { $idx = $matches[1][$i]; @@ -833,17 +833,17 @@ function daemonControl( $command, $daemon=false, $args=false ) { } $string = escapeshellcmd( $string ); #$string .= ' 2>/dev/null >&- <&- >/dev/null'; -Logger::Debug("daemonControl $string"); +ZM\Logger::Debug("daemonControl $string"); exec( $string ); } function zmcControl($monitor, $mode=false) { - $Monitor = new Monitor( $monitor ); + $Monitor = new ZM\Monitor( $monitor ); return $Monitor->zmcControl($mode); } function zmaControl($monitor, $mode=false) { - $Monitor = new Monitor($monitor); + $Monitor = new ZM\Monitor($monitor); return $Monitor->zmaControl($mode); } @@ -916,7 +916,7 @@ function zmaCheck( $monitor ) { } function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) { - $Event = new Event( $event ); + $Event = new ZM\Event( $event ); return $Event->getImageSrc( $frame, $scale, $captureOnly, $overwrite ); } @@ -940,7 +940,7 @@ function createListThumbnail( $event, $overwrite=false ) { $scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_HEIGHT)/$event['Height']; $thumbWidth = reScale( $event['Width'], $scale ); } else { - Fatal( "No thumbnail width or height specified, please check in Options->Web" ); + ZM\Fatal( "No thumbnail width or height specified, please check in Options->Web" ); } $imageData = getImageSrc( $event, $frame, $scale, false, $overwrite ); @@ -1196,11 +1196,11 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { if ( ! $StorageArea ) { for ( $j = 0; $j < count($terms); $j++ ) { if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) { - $StorageArea = new Storage($terms[$j]['val']); + $StorageArea = new ZM\Storage($terms[$j]['val']); break; } } // end foreach remaining term - if ( ! $StorageArea ) $StorageArea = new Storage(); + if ( ! $StorageArea ) $StorageArea = new ZM\Storage(); } // end no StorageArea found yet $filter['sql'] .= getDiskPercent( $StorageArea->Path() ); @@ -1210,7 +1210,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { if ( ! $StorageArea ) { for ( $j = $i; $j < count($terms); $j++ ) { if ( isset($terms[$i]['attr']) and $terms[$i]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) { - $StorageArea = new Storage($terms[$i]['val']); + $StorageArea = new ZM\Storage($terms[$i]['val']); } } // end foreach remaining term } // end no StorageArea found yet @@ -1242,7 +1242,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { } break; case 'StorageId': - $StorageArea = new Storage( $value ); + $StorageArea = new ZM\Storage( $value ); if ( $value != 'NULL' ) $value = dbEscape($value); break; @@ -1462,7 +1462,7 @@ function getDiskPercent($path = ZM_DIR_EVENTS) { } function getDiskBlocks() { - if ( ! $StorageArea ) $StorageArea = new Storage(); + if ( ! $StorageArea ) $StorageArea = new ZM\Storage(); $df = shell_exec( 'df '.escapeshellarg($StorageArea->Path() )); $space = -1; if ( preg_match( '/\s(\d+)\s+\d+\s+\d+%/ms', $df, $matches ) ) @@ -1847,17 +1847,17 @@ function coordsToPoints( $coords ) { function limitPoints( &$points, $min_x, $min_y, $max_x, $max_y ) { foreach ( $points as &$point ) { if ( $point['x'] < $min_x ) { - Logger::Debug('Limiting point x'.$point['x'].' to min_x ' . $min_x ); + ZM\Logger::Debug('Limiting point x'.$point['x'].' to min_x ' . $min_x ); $point['x'] = $min_x; } else if ( $point['x'] > $max_x ) { - Logger::Debug('Limiting point x'.$point['x'].' to max_x ' . $max_x ); + ZM\Logger::Debug('Limiting point x'.$point['x'].' to max_x ' . $max_x ); $point['x'] = $max_x; } if ( $point['y'] < $min_y ) { - Logger::Debug('Limiting point y'.$point['y'].' to min_y ' . $min_y ); + ZM\Logger::Debug('Limiting point y'.$point['y'].' to min_y ' . $min_y ); $point['y'] = $min_y; } else if ( $point['y'] > $max_y ) { - Logger::Debug('Limiting point y'.$point['y'].' to max_y ' . $max_y ); + ZM\Logger::Debug('Limiting point y'.$point['y'].' to max_y ' . $max_y ); $point['y'] = $max_y; } } // end foreach point @@ -1912,13 +1912,13 @@ function initX10Status() { if ( !isset($x10_status) ) { $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); if ( $socket < 0 ) { - Fatal( 'socket_create() failed: '.socket_strerror($socket) ); + ZM\Fatal( 'socket_create() failed: '.socket_strerror($socket) ); } $sock_file = ZM_PATH_SOCKS.'/zmx10.sock'; if ( @socket_connect( $socket, $sock_file ) ) { $command = 'status'; if ( !socket_write( $socket, $command ) ) { - Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); + ZM\Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); } socket_shutdown( $socket, 1 ); $x10Output = ''; @@ -1954,13 +1954,13 @@ function getDeviceStatusX10( $key ) { function setDeviceStatusX10( $key, $status ) { $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); if ( $socket < 0 ) { - Fatal( 'socket_create() failed: '.socket_strerror($socket) ); + ZM\Fatal( 'socket_create() failed: '.socket_strerror($socket) ); } $sock_file = ZM_PATH_SOCKS.'/zmx10.sock'; if ( @socket_connect( $socket, $sock_file ) ) { $command = "$status;$key"; if ( !socket_write( $socket, $command ) ) { - Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); + ZM\Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); } socket_shutdown( $socket, 1 ); $x10Response = socket_read( $socket, 256 ); @@ -1983,18 +1983,18 @@ function logState() { $state = 'ok'; $levelCounts = array( - Logger::FATAL => array( ZM_LOG_ALERT_FAT_COUNT, ZM_LOG_ALARM_FAT_COUNT ), - Logger::ERROR => array( ZM_LOG_ALERT_ERR_COUNT, ZM_LOG_ALARM_ERR_COUNT ), - Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ), + ZM\Logger::FATAL => array( ZM_LOG_ALERT_FAT_COUNT, ZM_LOG_ALARM_FAT_COUNT ), + ZM\Logger::ERROR => array( ZM_LOG_ALERT_ERR_COUNT, ZM_LOG_ALARM_ERR_COUNT ), + ZM\Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ), ); # This is an expensive request, as it has to hit every row of the Logs Table - $sql = 'SELECT Level, COUNT(Level) AS LevelCount FROM Logs WHERE Level < '.Logger::INFO.' AND TimeKey > unix_timestamp(now() - interval '.ZM_LOG_CHECK_PERIOD.' second) GROUP BY Level ORDER BY Level ASC'; + $sql = 'SELECT Level, COUNT(Level) AS LevelCount FROM Logs WHERE Level < '.ZM\Logger::INFO.' AND TimeKey > unix_timestamp(now() - interval '.ZM_LOG_CHECK_PERIOD.' second) GROUP BY Level ORDER BY Level ASC'; $counts = dbFetchAll($sql); if ( $counts ) { foreach ( $counts as $count ) { - if ( $count['Level'] <= Logger::PANIC ) - $count['Level'] = Logger::FATAL; + if ( $count['Level'] <= ZM\Logger::PANIC ) + $count['Level'] = ZM\Logger::FATAL; if ( !($levelCount = $levelCounts[$count['Level']]) ) { Error('Unexpected Log level '.$count['Level']); next; @@ -2026,15 +2026,15 @@ function checkJsonError($value) { $value = var_export($value,true); switch( json_last_error() ) { case JSON_ERROR_DEPTH : - Fatal( "Unable to decode JSON string '$value', maximum stack depth exceeded" ); + ZM\Fatal( "Unable to decode JSON string '$value', maximum stack depth exceeded" ); case JSON_ERROR_CTRL_CHAR : - Fatal( "Unable to decode JSON string '$value', unexpected control character found" ); + ZM\Fatal( "Unable to decode JSON string '$value', unexpected control character found" ); case JSON_ERROR_STATE_MISMATCH : - Fatal( "Unable to decode JSON string '$value', invalid or malformed JSON" ); + ZM\Fatal( "Unable to decode JSON string '$value', invalid or malformed JSON" ); case JSON_ERROR_SYNTAX : - Fatal( "Unable to decode JSON string '$value', syntax error" ); + ZM\Fatal( "Unable to decode JSON string '$value', syntax error" ); default : - Fatal( "Unable to decode JSON string '$value', unexpected error ".json_last_error() ); + ZM\Fatal( "Unable to decode JSON string '$value', unexpected error ".json_last_error() ); case JSON_ERROR_NONE: break; } @@ -2122,7 +2122,7 @@ define( 'HTTP_STATUS_BAD_REQUEST', 400 ); define( 'HTTP_STATUS_FORBIDDEN', 403 ); function ajaxError( $message, $code=HTTP_STATUS_OK ) { - Error( $message ); + ZM\Error( $message ); if ( function_exists( 'ajaxCleanup' ) ) ajaxCleanup(); if ( $code == HTTP_STATUS_OK ) { @@ -2168,7 +2168,7 @@ function cache_bust( $file ) { if ( file_exists(ZM_DIR_CACHE.'/'.$cacheFile) or symlink(ZM_PATH_WEB.'/'.$file, ZM_DIR_CACHE.'/'.$cacheFile) ) { return 'cache/'.$cacheFile; } else { - Warning("Failed linking $file to $cacheFile"); + ZM\Warning("Failed linking $file to $cacheFile"); } return $file; } @@ -2292,7 +2292,7 @@ function getStreamHTML( $monitor, $options = array() ) { $monitor->Name()); } else { if ( $options['mode'] == 'stream' ) { - Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' ); + ZM\Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' ); } $options['mode'] = 'single'; $streamSrc = $monitor->getStreamSrc( $options ); @@ -2308,7 +2308,7 @@ function getStreamMode( ) { $streamMode = 'jpeg'; } else { $streamMode = 'single'; - Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' ); + ZM\Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' ); } return $streamMode; } // end function getStreamMode @@ -2349,13 +2349,13 @@ function check_timezone() { #"); if ( $sys_tzoffset != $php_tzoffset ) - Fatal("ZoneMinder is not installed properly: php's date.timezone does not match the system timezone!"); + ZM\Fatal("ZoneMinder is not installed properly: php's date.timezone does not match the system timezone!"); if ( $sys_tzoffset != $mysql_tzoffset ) - Error("ZoneMinder is not installed properly: mysql's timezone does not match the system timezone! Event lists will display incorrect times."); + ZM\Error("ZoneMinder is not installed properly: mysql's timezone does not match the system timezone! Event lists will display incorrect times."); if (!ini_get('date.timezone') || !date_default_timezone_set(ini_get('date.timezone'))) - Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" ); + ZM\Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" ); } diff --git a/web/includes/logger.php b/web/includes/logger.php index 28d0ce902..1e37f708e 100644 --- a/web/includes/logger.php +++ b/web/includes/logger.php @@ -1,5 +1,6 @@
  • Logger::NOLOG ) { + if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) { if ( ! ZM_RUN_AUDIT ) { # zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly dbQuery('DELETE FROM Logs WHERE TimeKey < unix_timestamp( NOW() - interval '.ZM_LOG_DATABASE_LIMIT.') LIMIT 100'); @@ -355,13 +355,13 @@ if ($reload == 'reload') ob_start(); ?>
  • : Path()] = $area; } if ( ! isset($storage_paths[ZM_DIR_EVENTS]) ) { - array_push( $storage_areas, new Storage() ); + array_push( $storage_areas, new ZM\Storage() ); } $func = function($S){ $class = ''; diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 6f94580e2..3e149cfba 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -18,7 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -$servers = Server::find(null, array('order'=>'lower(Name)')); +$servers = ZM\Server::find(null, array('order'=>'lower(Name)')); $ServersById = array(); foreach ( $servers as $S ) { $ServersById[$S->Id()] = $S; @@ -37,7 +37,7 @@ foreach ( array('Group','Function','ServerId','StorageId','Status','MonitorId',' } session_write_close(); -$storage_areas = Storage::find(); +$storage_areas = ZM\Storage::find(); $StorageById = array(); foreach ( $storage_areas as $S ) { $StorageById[$S->Id()] = $S; @@ -52,7 +52,7 @@ $html = '; $GroupsById = array(); -foreach ( Group::find() as $G ) { +foreach ( ZM\Group::find() as $G ) { $GroupsById[$G->Id()] = $G; } @@ -61,8 +61,8 @@ if ( count($GroupsById) ) { $html .= ''; # This will end up with the group_id of the deepest selection $group_id = isset($_SESSION['Group']) ? $_SESSION['Group'] : null; - $html .= Group::get_group_dropdown(); - $groupSql = Group::get_group_sql($group_id); + $html .= ZM\Group::get_group_dropdown(); + $groupSql = ZM\Group::get_group_sql($group_id); $html .= ''; } @@ -188,12 +188,12 @@ $html .= htmlSelect( 'Status[]', $status_options, for ( $i = 0; $i < count($monitors); $i++ ) { if ( !visibleMonitor($monitors[$i]['Id']) ) { - Warning('Monitor '.$monitors[$i]['Id'].' is not visible'); + ZM\Logger::Warning('Monitor '.$monitors[$i]['Id'].' is not visible'); continue; } if ( isset($_SESSION['MonitorName']) ) { - $Monitor = new Monitor($monitors[$i]); + $Monitor = new ZM\Monitor($monitors[$i]); ini_set('track_errors', 'on'); $php_errormsg = ''; $regexp = $_SESSION['MonitorName']; @@ -209,7 +209,7 @@ $html .= htmlSelect( 'Status[]', $status_options, } if ( isset($_SESSION['Source']) ) { - $Monitor = new Monitor($monitors[$i]); + $Monitor = new ZM\Monitor($monitors[$i]); ini_set('track_errors', 'on'); $php_errormsg = ''; $regexp = $_SESSION['Source']; diff --git a/web/skins/classic/views/add_monitors.php b/web/skins/classic/views/add_monitors.php index 403c643c9..3b2f7590f 100644 --- a/web/skins/classic/views/add_monitors.php +++ b/web/skins/classic/views/add_monitors.php @@ -18,7 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canEdit( 'Monitors' ) ) { +if ( !canEdit('Monitors') ) { $view = 'error'; return; } @@ -61,8 +61,8 @@ xhtmlHeaders(__FILE__, translate('AddMonitors'));
  • - - + +
    '.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?> MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?> Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?> - Notes() && ($event->Notes() != 'Forced Web: ')) echo "
    ".$event->Notes()."
    " ?>
    StartTime())) . ( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
    %s%s%s%d%s%s%s%s
    Group
    Example Name MN1-30 INQ37.01http://10.34.152.20:2001/?action=streamExample Name Drivewayhttp://192.168.1.0/?action=stream MN1
    @@ -80,7 +80,7 @@ xhtmlHeaders(__FILE__, translate('AddMonitors')); ?> Id()] = $S; @@ -92,7 +92,7 @@ xhtmlHeaders(__FILE__, translate('AddMonitors')); Id()] = $S; diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index da583853d..5353b3412 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -230,7 +230,7 @@ ob_end_clean(); echo $table_head; for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $monitor = $displayMonitors[$monitor_i]; - $Monitor = new Monitor($monitor); + $Monitor = new ZM\Monitor($monitor); if ( $monitor_i and ( $monitor_i % 100 == 0 ) ) { echo ''; @@ -275,7 +275,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { ' : '>') . $monitor['Name'] ?>
    ', array_map(function($group_id){ - $Group = Group::find_one(array('Id'=>$group_id)); + $Group = ZM\Group::find_one(array('Id'=>$group_id)); if ( $Group ) { $Groups = $Group->Parents(); array_push( $Groups, $Group ); @@ -305,7 +305,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
    - Name(); ?> + Name(); ?> '. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.validHtmlStr($Monitor->Source()).'', canEdit('Monitors') ).''; diff --git a/web/skins/classic/views/control.php b/web/skins/classic/views/control.php index 0e5561544..fc8923d82 100644 --- a/web/skins/classic/views/control.php +++ b/web/skins/classic/views/control.php @@ -46,7 +46,7 @@ foreach ( dbFetchAll($sql, false, $params) as $row ) { foreach ( getSkinIncludes('includes/control_functions.php') as $includeFile ) require_once $includeFile; -$monitor = new Monitor($mid); +$monitor = new ZM\Monitor($mid); $focusWindow = true; diff --git a/web/skins/classic/views/cycle.php b/web/skins/classic/views/cycle.php index 2ea5e48ab..1e83e2c5b 100644 --- a/web/skins/classic/views/cycle.php +++ b/web/skins/classic/views/cycle.php @@ -50,7 +50,7 @@ foreach( $displayMonitors as &$row ) { $row['PopupScale'] = reScale(SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE); $row['connKey'] = generateConnKey(); - $monitors[] = new Monitor($row); + $monitors[] = new ZM\Monitor($row); } # end foreach Monitor if ( $monitors ) { diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 3a0bd250b..d608a7f58 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -26,7 +26,7 @@ if ( !canView('Events') ) { $eid = validInt( $_REQUEST['eid'] ); $fid = !empty($_REQUEST['fid'])?validInt($_REQUEST['fid']):1; -$Event = new Event( $eid ); +$Event = new ZM\Event( $eid ); if ( $user['MonitorIds'] ) { $monitor_ids = explode( ',', $user['MonitorIds'] ); if ( count($monitor_ids) and ! in_array( $Event->MonitorId(), $monitor_ids ) ) { diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index d5b3839f6..16b017326 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -80,12 +80,12 @@ $focusWindow = true; if ( $_POST ) { // I think this is basically so that a refresh doesn't repost - Logger::Debug("Redirecting to " . $_SERVER['REQUEST_URI']); + ZM\Logger::Debug('Redirecting to ' . $_SERVER['REQUEST_URI']); header('Location: ?view=' . $view.htmlspecialchars_decode($filterQuery).htmlspecialchars_decode($sortQuery).$limitQuery.'&page='.$page); exit(); } -$storage_areas = Storage::find(); +$storage_areas = ZM\Storage::find(); $StorageById = array(); foreach ( $storage_areas as $S ) { $StorageById[$S->Id()] = $S; @@ -146,7 +146,7 @@ $disk_space_total = 0; $results = dbQuery($eventsSql); while ( $event_row = dbFetchNext($results) ) { - $event = new Event($event_row); + $event = new ZM\Event($event_row); if ( $event_row['Archived'] ) $archived = true; else diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 3e4fe7969..1fad824f3 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -40,7 +40,7 @@ if ( isset($_SESSION['export']) ) { if (isset($_REQUEST['exportFormat'])) { if (!in_array($_REQUEST['exportFormat'], array('zip', 'tar'))) { - Error('Invalid exportFormat'); + ZM\Error('Invalid exportFormat'); return; } } diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index aa1ffc5c2..9f95d8c58 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -36,11 +36,11 @@ foreach ( dbFetchAll('SELECT * FROM Filters ORDER BY Name') as $row ) { $filterNames[$row['Id']] .= '&'; if ( isset($_REQUEST['Id']) && $_REQUEST['Id'] == $row['Id'] ) { - $filter = new Filter($row); + $filter = new ZM\Filter($row); } } if ( ! $filter ) { - $filter = new Filter(); + $filter = new ZM\Filter(); } if ( isset($_REQUEST['sort_field']) && isset($_REQUEST['filter']) ) { diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index ae69fecba..55ba1fe8a 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -29,7 +29,7 @@ $eid = validInt($_REQUEST['eid']); if ( !empty($_REQUEST['fid']) ) $fid = validInt($_REQUEST['fid']); -$Event = new Event($eid); +$Event = new ZM\Event($eid); $Monitor = $Event->Monitor(); if ( !empty($fid) ) { @@ -39,7 +39,7 @@ if ( !empty($fid) ) { } else { $frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $Event->MaxScore() ) ); } -$Frame = new Frame($frame); +$Frame = new ZM\Frame($frame); $maxFid = $Event->Frames(); @@ -63,7 +63,7 @@ $scale = $scale ?: "auto"; $imageData = $Event->getImageSrc( $frame, $scale, 0 ); if ( ! $imageData ) { - Error("No data found for Event $eid frame $fid"); + ZM\Error("No data found for Event $eid frame $fid"); $imageData = array(); } diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 83e3f69dd..3e146c958 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -23,7 +23,7 @@ if ( !canView('Events') ) { return; } require_once('includes/Frame.php'); -$Event = new Event( $_REQUEST['eid'] ); +$Event = new ZM\Event($_REQUEST['eid']); $sql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames WHERE EventID = ? ORDER BY FrameId'; $frames = dbFetchAll( $sql, NULL, array( $_REQUEST['eid'] ) ); @@ -62,7 +62,7 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id() ); diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index ac689a176..3f7629a75 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -24,9 +24,9 @@ if ( !canEdit('Groups') ) { } if ( !empty($_REQUEST['gid']) ) { - $newGroup = new Group($_REQUEST['gid']); + $newGroup = new ZM\Group($_REQUEST['gid']); } else { - $newGroup = new Group(); + $newGroup = new ZM\Group(); } xhtmlHeaders(__FILE__, translate('Group').' - '.$newGroup->Name()); @@ -51,7 +51,7 @@ xhtmlHeaders(__FILE__, translate('Group').' - '.$newGroup->Name()); Id()] = $Group; } diff --git a/web/skins/classic/views/groups.php b/web/skins/classic/views/groups.php index 9a6bf9242..5ae28a40a 100644 --- a/web/skins/classic/views/groups.php +++ b/web/skins/classic/views/groups.php @@ -28,7 +28,7 @@ $group_id = 0; $max_depth = 0; $Groups = array(); -foreach ( Group::find() as $Group ) { +foreach ( ZM\Group::find() as $Group ) { $Groups[$Group->Id()] = $Group; } diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index c887bb0e3..7c529790b 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -120,21 +120,21 @@ echo " };\n"; echo "\nvar Storage = [];\n"; $have_storage_zero = 0; -foreach ( Storage::find() as $Storage ) { +foreach ( ZM\Storage::find() as $Storage ) { echo 'Storage[' . $Storage->Id() . '] = ' . $Storage->to_json(). ";\n"; if ( $Storage->Id() == 0 ) $have_storage_zero = true; } if ( !$have_storage_zero ) { - $Storage = new Storage(); + $Storage = new ZM\Storage(); echo 'Storage[0] = ' . $Storage->to_json(). ";\n"; } echo "\nvar Servers = [];\n"; // Fall back to get Server paths, etc when no using multi-server mode -$Server = new Server(); +$Server = new ZM\Server(); echo 'Servers[0] = new Server(' . $Server->to_json(). ");\n"; -foreach ( Server::find() as $Server ) { +foreach ( ZM\Server::find() as $Server ) { echo 'Servers[' . $Server->Id() . '] = new Server(' . $Server->to_json(). ");\n"; } diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index cd082ec1b..d3c434a73 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -36,7 +36,7 @@ if ( ! $Server ) { $monitor = null; if ( ! empty($_REQUEST['mid']) ) { - $monitor = new Monitor( $_REQUEST['mid'] ); + $monitor = new ZM\Monitor( $_REQUEST['mid'] ); if ( $monitor and ZM_OPT_X10 ) $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['mid']) ); } @@ -44,7 +44,7 @@ if ( ! $monitor ) { $nextId = getTableAutoInc( 'Monitors' ); if ( isset( $_REQUEST['dupId'] ) ) { - $monitor = new Monitor( $_REQUEST['dupId'] ); + $monitor = new ZM\Monitor( $_REQUEST['dupId'] ); $monitor->GroupIds(); // have to load before we change the Id if ( ZM_OPT_X10 ) $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']) ); @@ -52,7 +52,7 @@ if ( ! $monitor ) { $monitor->Name( translate('Monitor').'-'.$nextId ); $monitor->Id( $nextId ); } else { - $monitor = new Monitor(); + $monitor = new ZM\Monitor(); $monitor->set( array( 'Id' => 0, 'Name' => translate('Monitor').'-'.$nextId, @@ -678,10 +678,8 @@ switch ( $tab ) { 'None','auto'=>'Auto'); - $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); - $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Server' ); - foreach ( $results as $row => $server_obj ) { - $servers[$server_obj->Id()] = $server_obj->Name(); + foreach ( ZM\Server::find(NULL, array('order'=>'lower(Name)')) as $Server ) { + $servers[$Server->Id()] = $Server->Name(); } echo htmlSelect( 'newMonitor[ServerId]', $servers, $monitor->ServerId() ); ?> @@ -689,10 +687,8 @@ switch ( $tab ) { 'Default'); - $result = dbQuery( 'SELECT * FROM Storage ORDER BY Name'); - $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' ); - foreach ( $results as $row => $storage_obj ) { - $storage_areas[$storage_obj->Id] = $storage_obj->Name(); + 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() ); ?> @@ -733,7 +729,7 @@ switch ( $tab ) { $i, @@ -247,13 +247,13 @@ function probeNetwork() { $arp_command = ZM_PATH_ARP; $result = explode(' ', $arp_command); if ( !is_executable($result[0]) ) { - Error("ARP compatible binary not found or not executable by the web user account. Verify ZM_PATH_ARP points to a valid arp tool."); + ZM\Error("ARP compatible binary not found or not executable by the web user account. Verify ZM_PATH_ARP points to a valid arp tool."); return; } $result = exec(escapeshellcmd($arp_command), $output, $status); if ( $status ) { - Error("Unable to probe network cameras, status is '$status'"); + ZM\Error("Unable to probe network cameras, status is '$status'"); return; } diff --git a/web/skins/classic/views/monitors.php b/web/skins/classic/views/monitors.php index a8d2e9d8d..3cf2f5edc 100644 --- a/web/skins/classic/views/monitors.php +++ b/web/skins/classic/views/monitors.php @@ -23,14 +23,14 @@ if ( !canEdit('Monitors') ) { return; } -$monitors = Monitor::find(array('Id' => $_REQUEST['mids'])); +$monitors = ZM\Monitor::find(array('Id' => $_REQUEST['mids'])); $monitor = $monitors[0]; -$servers = Server::find(); +$servers = ZM\Server::find(); $ServersById = array(); foreach ( $servers as $S ) { $ServersById[$S->Id()] = $S; } -$storage_areas = Storage::find(); +$storage_areas = ZM\Storage::find(); $StorageById = array(); foreach ( $storage_areas as $S ) { $StorageById[$S->Id()] = $S; diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index c0416997c..474333060 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -50,16 +50,16 @@ $scale = '100'; # actual if ( isset( $_REQUEST['scale'] ) ) { $scale = validInt($_REQUEST['scale']); - Logger::Debug("Setting scale from request to $scale"); + ZM\Logger::Debug("Setting scale from request to $scale"); } else if ( isset($_COOKIE['zmMontageScale']) ) { $scale = $_COOKIE['zmMontageScale']; - Logger::Debug("Setting scale from cookie to $scale"); + ZM\Logger::Debug("Setting scale from cookie to $scale"); } if ( ! $scale ) $scale = 100; -$layouts = MontageLayout::find(NULL, array('order'=>"lower('Name')")); +$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')")); $layoutsById = array(); foreach ( $layouts as $l ) { $layoutsById[$l->Id()] = $l; @@ -126,7 +126,7 @@ foreach( $displayMonitors as &$row ) { if ( ! isset($heights[$row['Height']]) ) { $heights[$row['Height']] = $row['Height']; } - $monitors[] = new Monitor($row); + $monitors[] = new ZM\Monitor($row); } # end foreach Monitor xhtmlHeaders(__FILE__, translate('Montage')); diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 53e8b51cf..563c9b52b 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -223,7 +223,7 @@ $monitors = array(); foreach( $displayMonitors as $row ) { if ( $row['Function'] == 'None' || $row['Type'] == 'WebSite' ) continue; - $Monitor = new Monitor($row); + $Monitor = new ZM\Monitor($row); $monitors[] = $Monitor; } diff --git a/web/skins/classic/views/onvifprobe.php b/web/skins/classic/views/onvifprobe.php index e715ab950..ed4dce6e3 100644 --- a/web/skins/classic/views/onvifprobe.php +++ b/web/skins/classic/views/onvifprobe.php @@ -36,12 +36,12 @@ function execONVIF( $cmd ) { if ( $status ) { $html_output = implode( '
    ', $output ); - Fatal( "Unable to probe network cameras, status is '$status'. Output was:

    + ZM\Fatal( "Unable to probe network cameras, status is '$status'. Output was:

    $html_output

    Please the following command from a command line for more information:

    $shell_command" ); } else { - Logger::Debug( "Results from probe: " . implode( '
    ', $output ) ); + ZM\Logger::Debug( "Results from probe: " . implode( '
    ', $output ) ); } return $output; @@ -73,7 +73,7 @@ function probeCameras( $localIp ) { } elseif ( $tokens[1] == 'location' ) { // $camera['location'] = $tokens[2]; } else { - Logger::Debug('Unknown token ' . $tokens[1]); + ZM\Logger::Debug('Unknown token ' . $tokens[1]); } } } // end foreach token @@ -109,7 +109,7 @@ function probeProfiles( $device_ep, $soapversion, $username, $password ) { ); $profiles[] = $profile; } else { - Logger::Debug("Line did not match preg: $line"); + ZM\Logger::Debug("Line did not match preg: $line"); } } // end foreach line } // end if results from execONVIF @@ -190,7 +190,7 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {

    - +

    @@ -206,12 +206,12 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) { //==== STEP 2 ============================================================ } else if($_REQUEST['step'] == '2') { if ( empty($_REQUEST['probe']) ) - Fatal('No probe passed in request. Please go back and try again.'); + ZM\Fatal('No probe passed in request. Please go back and try again.'); #|| empty($_REQUEST['username']) || #empty($_REQUEST['password']) ) $probe = json_decode(base64_decode($_REQUEST['probe'])); - Logger::Debug(print_r($probe,true)); + ZM\Logger::Debug(print_r($probe,true)); foreach ( $probe as $name=>$value ) { if ( isset($value) ) { $monitor[$name] = $value; diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 8503d1642..3078029d5 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -230,7 +230,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI Id(), 'zmServer', 'server', validHtmlStr($Server->Name()), $canEdit) ?> @@ -287,7 +287,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI -'lower(Name)') ) as $Storage ) { ?> +'lower(Name)') ) as $Storage ) { ?> Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Id()), $canEdit ) ?> Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?> diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 70808138e..c7517728e 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -62,7 +62,7 @@ if ( count($selected_monitor_ids) ) { } parseFilter($filter); $filterQuery = $filter['query']; -Logger::Debug($filterQuery); +ZM\Logger::Debug($filterQuery); $eventsSql = 'SELECT *, UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs, @@ -83,12 +83,12 @@ $eventsSql .= ' ORDER BY Id ASC'; $result = dbQuery($eventsSql); if ( !$result ) { - Fatal('SQL-ERR'); + ZM\Fatal('SQL-ERR'); return; } $EventsByMonitor = array(); while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { - $Event = new Event($event); + $Event = new ZM\Event($event); if ( ! isset($EventsByMonitor[$event['MonitorId']]) ) $EventsByMonitor[$event['MonitorId']] = array( 'Events'=>array(), 'MinGap'=>0, 'MaxGap'=>0, 'FileMissing'=>array(), 'ZeroSize'=>array() ); @@ -147,7 +147,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { ">
    ', array_map(function($group_id){ - $Group = new Group($group_id); + $Group = new ZM\Group($group_id); $Groups = $Group->Parents(); array_push($Groups, $Group); return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); diff --git a/web/skins/classic/views/server.php b/web/skins/classic/views/server.php index 0c028b8c1..67e15d71a 100644 --- a/web/skins/classic/views/server.php +++ b/web/skins/classic/views/server.php @@ -23,7 +23,7 @@ if ( !canEdit('System') ) { return; } -$Server = new Server($_REQUEST['id']); +$Server = new ZM\Server($_REQUEST['id']); if ( $_REQUEST['id'] and ! $Server->Id() ) { $view = 'error'; return; @@ -97,9 +97,8 @@ xhtmlHeaders(__FILE__, translate('Server').' - '.$Server->Name());
    - - - + +
    diff --git a/web/skins/classic/views/storage.php b/web/skins/classic/views/storage.php index 8da0ba5b5..93dd788b7 100644 --- a/web/skins/classic/views/storage.php +++ b/web/skins/classic/views/storage.php @@ -48,7 +48,7 @@ $scheme_options = array( 'Shallow' => translate('Shallow'), ); -$servers = Server::find( null, array('order'=>'lower(Name)') ); +$servers = ZM\Server::find( null, array('order'=>'lower(Name)') ); $ServersById = array(); foreach ( $servers as $S ) { $ServersById[$S->Id()] = $S; diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index acf4bcd11..8a55e607d 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -757,7 +757,6 @@ if ( $mode == 'overlay' ) { echo drawYGrid( $chart, $majYScale, 'majLabelY', 'majTickY', 'majGridY graphWidth' ); } echo drawXGrid( $chart, $majXScale, 'majLabelX', 'majTickX', 'majGridX graphHeight', 'zoom graphHeight' ); -Warning("Mode: $mode"); if ( $mode == 'overlay' ) { ?>
    diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index 6aae4808d..13dd0532e 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -37,7 +37,7 @@ if ( ! visibleMonitor($mid) ) { return; } -$monitor = new Monitor($mid); +$monitor = new ZM\Monitor($mid); #Whether to show the controls button $showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' ); diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index 66f379e90..fd0daf13d 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -54,7 +54,7 @@ foreach ( getEnumValues( 'Zones', 'CheckMethod' ) as $optCheckMethod ) { $optCheckMethods[$optCheckMethod] = $optCheckMethod; } -$monitor = new Monitor( $mid ); +$monitor = new ZM\Monitor( $mid ); $minX = 0; $maxX = $monitor->Width()-1; diff --git a/web/views/archive.php b/web/views/archive.php index c45c475ce..db6e66fe7 100644 --- a/web/views/archive.php +++ b/web/views/archive.php @@ -43,7 +43,7 @@ if ( $archivetype ) { if ( $mimetype ) { $filename = "zmExport.$file_ext"; $filename_path = ZM_DIR_EXPORTS.'/'.$filename; - Logger::Debug("downloading archive from $filename_path"); + ZM\Logger::Debug("downloading archive from $filename_path"); if ( is_readable($filename_path) ) { ob_clean(); header("Content-type: application/$mimetype" ); @@ -51,16 +51,16 @@ if ( $archivetype ) { header('Content-Length: ' . filesize($filename_path) ); set_time_limit(0); if ( ! @readfile( $filename_path ) ) { - Error("Error sending $filename_path"); + ZM\Error("Error sending $filename_path"); } } else { - Error("$filename_path does not exist or is not readable."); + ZM\Error("$filename_path does not exist or is not readable."); } } else { - Error("Unsupported archive type specified. Supported archives are tar and zip"); + ZM\Error("Unsupported archive type specified. Supported archives are tar and zip"); } } else { - Error("No archive type given to archive.php. Please specify a tar or zip archive."); + ZM\Error("No archive type given to archive.php. Please specify a tar or zip archive."); } ?> diff --git a/web/views/image.php b/web/views/image.php index b30d99ba6..ebb624580 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -64,16 +64,16 @@ if ( empty($_REQUEST['path']) ) { if ( empty($_REQUEST['fid']) ) { header('HTTP/1.0 404 Not Found'); - Fatal('No Frame ID specified'); + ZM\Fatal('No Frame ID specified'); return; } if ( !empty($_REQUEST['eid']) ) { - Logger::Debug("Loading by eid"); - $Event = Event::find_one(array('Id'=>$_REQUEST['eid'])); + ZM\Logger::Debug("Loading by eid"); + $Event = ZM\Event::find_one(array('Id'=>$_REQUEST['eid'])); if ( !$Event ) { header('HTTP/1.0 404 Not Found'); - Fatal('Event '.$_REQUEST['eid'].' Not found'); + ZM\Fatal('Event '.$_REQUEST['eid'].' Not found'); return; } @@ -81,19 +81,19 @@ if ( empty($_REQUEST['path']) ) { $path = $Event->Path().'/objdetect.jpg'; if ( !file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + ZM\Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); } - $Frame = new Frame(); + $Frame = new ZM\Frame(); $Frame->Id('objdetect'); } else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame - $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), + $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), array('order'=>'FrameId ASC')); if ( !$Frame ) { # no alarms, get first one I find - $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'])); + $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'])); if ( !$Frame ) { - Warning('No frame found for event '.$_REQUEST['eid']); - $Frame = new Frame(); + ZM\Warning('No frame found for event '.$_REQUEST['eid']); + $Frame = new ZM\Frame(); $Frame->Delta(1); $Frame->FrameId(1); } @@ -106,12 +106,12 @@ if ( empty($_REQUEST['path']) ) { $path = $Event->Path().'/alarm.jpg'; } } else if ( $_REQUEST['fid'] == 'snapshot' ) { - $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Score'=>$Event->MaxScore())); + $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Score'=>$Event->MaxScore())); if ( !$Frame ) - $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'])); + $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'])); if ( !$Frame ) { - Warning('No frame found for event ' . $_REQUEST['eid']); - $Frame = new Frame(); + ZM\Warning('No frame found for event ' . $_REQUEST['eid']); + $Frame = new ZM\Frame(); $Frame->Delta(1); $Frame->FrameId('snapshot'); } @@ -124,7 +124,7 @@ if ( empty($_REQUEST['path']) ) { } } else { - $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'FrameId'=>$_REQUEST['fid'])); + $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'FrameId'=>$_REQUEST['fid'])); if ( ! $Frame ) { $previousBulkFrame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND FrameId < ? ORDER BY FrameID DESC LIMIT 1', @@ -135,72 +135,72 @@ if ( empty($_REQUEST['path']) ) { NULL, array($_REQUEST['eid'], $_REQUEST['fid']) ); if ( $previousBulkFrame and $nextBulkFrame ) { - $Frame = new Frame($previousBulkFrame); + $Frame = new ZM\Frame($previousBulkFrame); $Frame->FrameId($_REQUEST['fid']); $percentage = ($Frame->FrameId() - $previousBulkFrame['FrameId']) / ($nextBulkFrame['FrameId'] - $previousBulkFrame['FrameId']); $Frame->Delta($previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100); - Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame['Delta'] . " + nextdelta:" . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage ); + ZM\Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame['Delta'] . " + nextdelta:" . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage ); } else { - Fatal('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')'); + ZM\Fatal('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')'); } } // Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; - Logger::Debug("Path: $path"); + ZM\Logger::Debug("Path: $path"); } } else { # If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame # - $Frame = Frame::find_one(array('Id'=>$_REQUEST['fid'])); + $Frame = ZM\Frame::find_one(array('Id'=>$_REQUEST['fid'])); if ( !$Frame ) { header('HTTP/1.0 404 Not Found'); - Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found'); + ZM\Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found'); return; } - $Event = Event::find_one(array('Id'=>$Frame->EventId())); + $Event = ZM\Event::find_one(array('Id'=>$Frame->EventId())); if ( !$Event ) { header('HTTP/1.0 404 Not Found'); - Fatal('Event ' . $Frame->EventId() . ' Not Found'); + ZM\Fatal('Event ' . $Frame->EventId() . ' Not Found'); return; } $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; } # end if have eid if ( !file_exists($path) ) { - Logger::Debug("$path does not exist"); + ZM\Logger::Debug("$path does not exist"); # Generate the frame JPG if ( ($show == 'capture') and $Event->DefaultVideo() ) { if ( !file_exists($Event->Path().'/'.$Event->DefaultVideo()) ) { header('HTTP/1.0 404 Not Found'); - Fatal("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() ); + ZM\Fatal("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() ); } $command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -frames:v 1 '.$path; #$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path; #$command ='ffmpeg -v 0 -i '.$Storage->Path().'/'.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path; - Logger::Debug("Running $command"); + ZM\Logger::Debug("Running $command"); $output = array(); $retval = 0; exec( $command, $output, $retval ); - Logger::Debug("Command: $command, retval: $retval, output: " . implode("\n", $output)); + ZM\Logger::Debug("Command: $command, retval: $retval, output: " . implode("\n", $output)); if ( ! file_exists( $path ) ) { header('HTTP/1.0 404 Not Found'); - Fatal("Can't create frame images from video for this event (".$Event->DefaultVideo() ); + ZM\Fatal("Can't create frame images from video for this event (".$Event->DefaultVideo() ); } # Generating an image file will use up more disk space, so update the Event record. $Event->DiskSpace(null); $Event->save(); } else { header('HTTP/1.0 404 Not Found'); - Fatal("Can't create frame $show images from video because there is no video file for this event at ". + ZM\Fatal("Can't create frame $show images from video because there is no video file for this event at ". $Event->Path().'/'.$Event->DefaultVideo() ); } } # end if ! file_exists($path) } else { - Warning('Loading images by path is deprecated'); + ZM\Warning('Loading images by path is deprecated'); $dir_events = realpath(ZM_DIR_EVENTS); $path = realpath($dir_events . '/' . $_REQUEST['path']); $pos = strpos($path, $dir_events); @@ -223,7 +223,7 @@ if ( empty($_REQUEST['path']) ) { } if ( !file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - Fatal("Image not found at $path"); + ZM\Fatal("Image not found at $path"); } } @@ -239,7 +239,7 @@ if ( !empty($_REQUEST['scale']) ) { $width = 0; if ( !empty($_REQUEST['width']) ) { -Logger::Debug("Setting width: " . $_REQUEST['width']); +ZM\Logger::Debug("Setting width: " . $_REQUEST['width']); if ( is_numeric($_REQUEST['width']) ) { $x = $_REQUEST['width']; if ( $x >= 10 and $x <= 8000 ) @@ -257,7 +257,7 @@ if ( !empty($_REQUEST['height']) ) { } if ( $errorText ) { - Error($errorText); + ZM\Error($errorText); } else { # Clears the output buffer. Not sure what is there, but have had troubles. ob_end_clean(); @@ -269,10 +269,10 @@ if ( $errorText ) { header('Content-Disposition: inline; filename="' . $filename . '"'); } if ( !readfile($path) ) { - Error('No bytes read from '. $path); + ZM\Error('No bytes read from '. $path); } } else { - Logger::Debug("Doing a scaled image: scale($scale) width($width) height($height)"); + ZM\Logger::Debug("Doing a scaled image: scale($scale) width($width) height($height)"); $i = 0; if ( ! ( $width && $height ) ) { $i = imagecreatefromjpeg($path); @@ -285,10 +285,10 @@ if ( $errorText ) { $width = ($height * $oldWidth) / $oldHeight; } elseif ( $width != 0 && $height == 0 ) { $height = ($width * $oldHeight) / $oldWidth; -Logger::Debug("Figuring out height using width: $height = ($width * $oldHeight) / $oldWidth"); +ZM\Logger::Debug("Figuring out height using width: $height = ($width * $oldHeight) / $oldWidth"); } if ( $width == $oldWidth && $height == $oldHeight ) { - Warning('No change to width despite scaling.'); + ZM\Warning('No change to width despite scaling.'); } } @@ -299,7 +299,7 @@ Logger::Debug("Figuring out height using width: $height = ($width * $oldHeight) header('Content-Disposition: inline; filename="' . $filename . '"'); } if ( !( file_exists($scaled_path) and readfile($scaled_path) ) ) { - Logger::Debug("Cached scaled image does not exist at $scaled_path or is no good.. Creating it"); + ZM\Logger::Debug("Cached scaled image does not exist at $scaled_path or is no good.. Creating it"); ob_start(); if ( !$i ) $i = imagecreatefromjpeg($path); @@ -312,12 +312,12 @@ Logger::Debug("Figuring out height using width: $height = ($width * $oldHeight) ob_end_clean(); echo $scaled_jpeg_data; } else { - Logger::Debug("Sending $scaled_path"); + ZM\Logger::Debug("Sending $scaled_path"); $bytes = readfile($scaled_path); if ( !$bytes ) { - Error('No bytes read from '. $scaled_path); + ZM\Error('No bytes read from '. $scaled_path); } else { - Logger::Debug("$bytes sent"); + ZM\Logger::Debug("$bytes sent"); } } } diff --git a/web/views/view_video.php b/web/views/view_video.php index 9bba64e69..9d04fb1b2 100644 --- a/web/views/view_video.php +++ b/web/views/view_video.php @@ -38,19 +38,19 @@ $path = ''; $Event = null; if ( ! empty($_REQUEST['eid']) ) { - $Event = new Event($_REQUEST['eid']); + $Event = new ZM\Event($_REQUEST['eid']); $path = $Event->Path().'/'.$Event->DefaultVideo(); - Logger::Debug("Path: $path"); + ZM\Logger::Debug("Path: $path"); } else if ( ! empty($_REQUEST['event_id']) ) { - $Event = new Event($_REQUEST['event_id']); + $Event = new ZM\Event($_REQUEST['event_id']); $path = $Event->Path().'/'.$Event->DefaultVideo(); - Logger::Debug("Path: $path"); + ZM\Logger::Debug("Path: $path"); } else { $errorText = 'No video path'; } if ( $errorText ) { - Error($errorText); + ZM\Error($errorText); header('HTTP/1.0 404 Not Found'); die(); } @@ -68,14 +68,14 @@ $end = $size-1; $length = $size; if ( isset($_SERVER['HTTP_RANGE']) ) { - Logger::Debug('Using Range ' . $_SERVER['HTTP_RANGE']); + ZM\Logger::Debug('Using Range ' . $_SERVER['HTTP_RANGE']); if ( preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches) ) { $begin = intval($matches[1]); if ( ! empty($matches[2]) ) { $end = intval($matches[2]); } $length = $end - $begin + 1; - Logger::Debug("Using Range $begin $end size: $size, length: $length"); + ZM\Logger::Debug("Using Range $begin $end size: $size, length: $length"); } } # end if HTTP_RANGE From 410cb70ddb8801d328c3dc225c6d96d4d3b833b9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 22 Feb 2019 09:20:54 -0500 Subject: [PATCH 91/92] get rid of js that just does the form submit. Upgrade the button from an input to a button. Use 0 and 1 instead of accept and decline, which allows us to pre-select the current value of ZM_TELEMETRY_DATA. So that if you had previously declined, you won't accidentally accept. This fixes the reported error that choosing decline would cause the setting to not be saved and the privacy popup to happen again. (#2534) --- web/includes/actions/privacy.php | 8 ++++---- web/skins/classic/views/js/privacy.js | 10 ---------- web/skins/classic/views/privacy.php | 27 +++++++++++++-------------- 3 files changed, 17 insertions(+), 28 deletions(-) delete mode 100644 web/skins/classic/views/js/privacy.js diff --git a/web/includes/actions/privacy.php b/web/includes/actions/privacy.php index 5712d5b40..5877bb60d 100644 --- a/web/includes/actions/privacy.php +++ b/web/includes/actions/privacy.php @@ -23,14 +23,14 @@ if ( !canEdit('System') ) { return; } -if ( ($action == 'privacy') && isset($_REQUEST['option']) ) { - switch( $_REQUEST['option'] ) { - case 'decline' : +if ( ($action == 'privacy') && isset($_POST['option']) ) { + switch( $_POST['option'] ) { + case '0' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_TELEMETRY_DATA'"); $redirect = '?view=console'; break; - case 'accept' : + case '1' : dbQuery("UPDATE Config SET Value = '0' WHERE Name = 'ZM_SHOW_PRIVACY'"); dbQuery("UPDATE Config SET Value = '1' WHERE Name = 'ZM_TELEMETRY_DATA'"); $redirect = '?view=console'; diff --git a/web/skins/classic/views/js/privacy.js b/web/skins/classic/views/js/privacy.js deleted file mode 100644 index bbf17f864..000000000 --- a/web/skins/classic/views/js/privacy.js +++ /dev/null @@ -1,10 +0,0 @@ -function submitForm( element ) { - var form = element.form; - if ( form.option.selectedIndex == 0 ) { - form.view.value = currentView; - } else { - form.view.value = 'none'; - } - form.submit(); -} - diff --git a/web/skins/classic/views/privacy.php b/web/skins/classic/views/privacy.php index 21c0bdb59..d82e4327f 100644 --- a/web/skins/classic/views/privacy.php +++ b/web/skins/classic/views/privacy.php @@ -18,20 +18,19 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canEdit( 'System' ) ) -{ - $view = "error"; - return; +if ( !canEdit('System') ) { + $view = 'error'; + return; } $options = array( - "accept" => translate('Accept'), - "decline" => translate('Decline'), + '1' => translate('Accept'), + '0' => translate('Decline'), ); $focusWindow = true; -xhtmlHeaders(__FILE__, translate('Privacy') ); +xhtmlHeaders(__FILE__, translate('Privacy')); ?>
    @@ -41,31 +40,31 @@ xhtmlHeaders(__FILE__, translate('Privacy') );
    - +

    -
    +

    -
    +

    -
    +

    -
    +

    -

    +

    - +
    From 0a7667f2d03332958664a16a261eec0681c03e5c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 22 Feb 2019 09:23:06 -0500 Subject: [PATCH 92/92] Use buttons instead of divs and inputs (#2522) --- web/skins/classic/css/base/views/control.css | 3 + .../classic/includes/control_functions.php | 184 +++++++++--------- 2 files changed, 95 insertions(+), 92 deletions(-) diff --git a/web/skins/classic/css/base/views/control.css b/web/skins/classic/css/base/views/control.css index 90757a146..2c9faf455 100644 --- a/web/skins/classic/css/base/views/control.css +++ b/web/skins/classic/css/base/views/control.css @@ -15,6 +15,9 @@ .ptzControls input.ptzTextBtn { margin-top: 2px; } +.ptzControls button { + border: none; +} .ptzControls .controlsPanel { margin: 0 auto; diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index ec51458ee..41d4053c5 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -21,104 +21,104 @@ function getControlCommands( $monitor ) { $cmds = array(); - $cmds['Wake'] = "wake"; - $cmds['Sleep'] = "sleep"; - $cmds['Reset'] = "reset"; + $cmds['Wake'] = 'wake'; + $cmds['Sleep'] = 'sleep'; + $cmds['Reset'] = 'reset'; - $cmds['PresetSet'] = "presetSet"; - $cmds['PresetGoto'] = "presetGoto"; - $cmds['PresetHome'] = "presetHome"; + $cmds['PresetSet'] = 'presetSet'; + $cmds['PresetGoto'] = 'presetGoto'; + $cmds['PresetHome'] = 'presetHome'; if ( $monitor->CanZoom() ) { if ( $monitor->CanZoomCon() ) - $cmds['ZoomRoot'] = "zoomCon"; + $cmds['ZoomRoot'] = 'zoomCon'; elseif ( $monitor->CanZoomRel() ) - $cmds['ZoomRoot'] = "zoomRel"; + $cmds['ZoomRoot'] = 'zoomRel'; elseif ( $monitor->CanZoomAbs() ) - $cmds['ZoomRoot'] = "zoomAbs"; - $cmds['ZoomTele'] = $cmds['ZoomRoot']."Tele"; - $cmds['ZoomWide'] = $cmds['ZoomRoot']."Wide"; - $cmds['ZoomStop'] = "zoomStop"; - $cmds['ZoomAuto'] = "zoomAuto"; - $cmds['ZoomMan'] = "zoomMan"; + $cmds['ZoomRoot'] = 'zoomAbs'; + $cmds['ZoomTele'] = $cmds['ZoomRoot'].'Tele'; + $cmds['ZoomWide'] = $cmds['ZoomRoot'].'Wide'; + $cmds['ZoomStop'] = 'zoomStop'; + $cmds['ZoomAuto'] = 'zoomAuto'; + $cmds['ZoomMan'] = 'zoomMan'; } if ( $monitor->CanFocus() ) { if ( $monitor->CanFocusCon() ) - $cmds['FocusRoot'] = "focusCon"; + $cmds['FocusRoot'] = 'focusCon'; elseif ( $monitor->CanFocusRel() ) - $cmds['FocusRoot'] = "focusRel"; + $cmds['FocusRoot'] = 'focusRel'; elseif ( $monitor->CanFocusAbs() ) - $cmds['FocusRoot'] = "focusAbs"; - $cmds['FocusFar'] = $cmds['FocusRoot']."Far"; - $cmds['FocusNear'] = $cmds['FocusRoot']."Near"; - $cmds['FocusStop'] = "focusStop"; - $cmds['FocusAuto'] = "focusAuto"; - $cmds['FocusMan'] = "focusMan"; + $cmds['FocusRoot'] = 'focusAbs'; + $cmds['FocusFar'] = $cmds['FocusRoot'].'Far'; + $cmds['FocusNear'] = $cmds['FocusRoot'].'Near'; + $cmds['FocusStop'] = 'focusStop'; + $cmds['FocusAuto'] = 'focusAuto'; + $cmds['FocusMan'] = 'focusMan'; } if ( $monitor->CanIris() ) { if ( $monitor->CanIrisCon() ) - $cmds['IrisRoot'] = "irisCon"; + $cmds['IrisRoot'] = 'irisCon'; elseif ( $monitor->CanIrisRel() ) - $cmds['IrisRoot'] = "irisRel"; + $cmds['IrisRoot'] = 'irisRel'; elseif ( $monitor->CanIrisAbs() ) - $cmds['IrisRoot'] = "irisAbs"; - $cmds['IrisOpen'] = $cmds['IrisRoot']."Open"; - $cmds['IrisClose'] = $cmds['IrisRoot']."Close"; - $cmds['IrisStop'] = "irisStop"; - $cmds['IrisAuto'] = "irisAuto"; - $cmds['IrisMan'] = "irisMan"; + $cmds['IrisRoot'] = 'irisAbs'; + $cmds['IrisOpen'] = $cmds['IrisRoot'].'Open'; + $cmds['IrisClose'] = $cmds['IrisRoot'].'Close'; + $cmds['IrisStop'] = 'irisStop'; + $cmds['IrisAuto'] = 'irisAuto'; + $cmds['IrisMan'] = 'irisMan'; } if ( $monitor->CanWhite() ) { if ( $monitor->CanWhiteCon() ) - $cmds['WhiteRoot'] = "whiteCon"; + $cmds['WhiteRoot'] = 'whiteCon'; elseif ( $monitor->CanWhiteRel() ) - $cmds['WhiteRoot'] = "whiteRel"; + $cmds['WhiteRoot'] = 'whiteRel'; elseif ( $monitor->CanWhiteAbs() ) - $cmds['WhiteRoot'] = "whiteAbs"; - $cmds['WhiteIn'] = $cmds['WhiteRoot']."In"; - $cmds['WhiteOut'] = $cmds['WhiteRoot']."Out"; - $cmds['WhiteAuto'] = "whiteAuto"; - $cmds['WhiteMan'] = "whiteMan"; + $cmds['WhiteRoot'] = 'whiteAbs'; + $cmds['WhiteIn'] = $cmds['WhiteRoot'].'In'; + $cmds['WhiteOut'] = $cmds['WhiteRoot'].'Out'; + $cmds['WhiteAuto'] = 'whiteAuto'; + $cmds['WhiteMan'] = 'whiteMan'; } if ( $monitor->CanGain() ) { if ( $monitor->CanGainCon() ) - $cmds['GainRoot'] = "gainCon"; + $cmds['GainRoot'] = 'gainCon'; elseif ( $monitor->CanGainRel() ) - $cmds['GainRoot'] = "gainRel"; + $cmds['GainRoot'] = 'gainRel'; elseif ( $monitor->CanGainAbs() ) - $cmds['GainRoot'] = "gainAbs"; - $cmds['GainUp'] = $cmds['GainRoot']."Up"; - $cmds['GainDown'] = $cmds['GainRoot']."Down"; - $cmds['GainAuto'] = "gainAuto"; - $cmds['GainMan'] = "gainMan"; + $cmds['GainRoot'] = 'gainAbs'; + $cmds['GainUp'] = $cmds['GainRoot'].'Up'; + $cmds['GainDown'] = $cmds['GainRoot'].'Down'; + $cmds['GainAuto'] = 'gainAuto'; + $cmds['GainMan'] = 'gainMan'; } if ( $monitor->CanMove() ) { if ( $monitor->CanMoveCon() ) { - $cmds['MoveRoot'] = "moveCon"; - $cmds['Center'] = "moveStop"; + $cmds['MoveRoot'] = 'moveCon'; + $cmds['Center'] = 'moveStop'; } elseif ( $monitor->CanMoveRel() ) { - $cmds['MoveRoot'] = "moveRel"; + $cmds['MoveRoot'] = 'moveRel'; $cmds['Center'] = $cmds['PresetHome']; } elseif ( $monitor->CanMoveAbs() ) { - $cmds['MoveRoot'] = "moveAbs"; + $cmds['MoveRoot'] = 'moveAbs'; $cmds['Center'] = $cmds['PresetHome']; } else { $cmds['MoveRoot'] = ''; } - $cmds['MoveUp'] = $cmds['MoveRoot']."Up"; - $cmds['MoveDown'] = $cmds['MoveRoot']."Down"; - $cmds['MoveLeft'] = $cmds['MoveRoot']."Left"; - $cmds['MoveRight'] = $cmds['MoveRoot']."Right"; - $cmds['MoveUpLeft'] = $cmds['MoveRoot']."UpLeft"; - $cmds['MoveUpRight'] = $cmds['MoveRoot']."UpRight"; - $cmds['MoveDownLeft'] = $cmds['MoveRoot']."DownLeft"; - $cmds['MoveDownRight'] = $cmds['MoveRoot']."DownRight"; + $cmds['MoveUp'] = $cmds['MoveRoot'].'Up'; + $cmds['MoveDown'] = $cmds['MoveRoot'].'Down'; + $cmds['MoveLeft'] = $cmds['MoveRoot'].'Left'; + $cmds['MoveRight'] = $cmds['MoveRoot'].'Right'; + $cmds['MoveUpLeft'] = $cmds['MoveRoot'].'UpLeft'; + $cmds['MoveUpRight'] = $cmds['MoveRoot'].'UpRight'; + $cmds['MoveDownLeft'] = $cmds['MoveRoot'].'DownLeft'; + $cmds['MoveDownRight'] = $cmds['MoveRoot'].'DownRight'; } return( $cmds ); } @@ -128,15 +128,15 @@ function controlFocus( $monitor, $cmds ) { ?>
    -
    -
    CanFocusCon() ) { ?> onclick="controlCmd('')">
    -
    + + +
    CanAutoFocus() ) { ?> - - + + @@ -152,15 +152,15 @@ function controlZoom( $monitor, $cmds ) { ?>
    -
    -
    CanZoomCon() ) { ?> onclick="controlCmd('')">
    -
    + + +
    CanAutoZoom() ) { ?> - - + + @@ -175,15 +175,15 @@ function controlIris( $monitor, $cmds ) { ?>
    -
    -
    CanIrisCon() ) { ?> onclick="controlCmd('')">
    -
    + + +
    CanAutoIris() ) { ?> - - + + @@ -199,15 +199,15 @@ function controlWhite( $monitor, $cmds ) { ?>
    -
    -
    CanWhiteCon() ) { ?> onclick="controlCmd('')">
    -
    + + +
    CanAutoWhite() ) { ?> - - + + @@ -229,19 +229,19 @@ function controlPanTilt( $monitor, $cmds ) { $hasTilt = $monitor->CanTilt(); $hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag(); ?> -
    -
    -
    -
    + + + + -
    + -
    + -
    -
    -
    -
    + + + +
    NumPresets(); $i++ ) { ?> - +
    HasHomePreset() ) { ?> - + CanSleep() ) { ?> - + CanReset() ) { ?> - +