So I run a CCTV system based on the excellent open source Zoneminder, running on a pretty entry level ex-lease PC I bought from PBTech.
What I want to do is embed one of the cameras into a web site.
So my steps are going to be:
- Setup a Zoneminder user for public access.
- Write a small PHP proxy script.
- Profit!
Prerequisites
I’m not going to talk you through setting up a Debian server.
Nor am I going to talk you through setting up a Zoneminder server on a Debian server.
I will assume that you have these things running.
I’ll also assume that you have the Zoneminder console running from a virtual sub directory in Apache (in my case /zm/ ).
But just in case, here’s a quick reminder of the Apache config:
# Remember to enable cgi mod (i.e. "a2enmod cgi").
ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
<Directory "/usr/lib/zoneminder/cgi-bin">
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AllowOverride All
Require all granted
</Directory>
# Order matters. This alias must come first.
Alias /zm/cache /var/cache/zoneminder/cache
<Directory /var/cache/zoneminder/cache>
Options -Indexes +FollowSymLinks
AllowOverride None
<IfModule mod_authz_core.c>
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
Alias /zm /usr/share/zoneminder/www
<Directory /usr/share/zoneminder/www>
Options -Indexes +FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
# For better visibility, the following directives have been migrated from the
# default .htaccess files included with the CakePHP project.
# Parameters not set here are inherited from the parent directive above.
<Directory "/usr/share/zoneminder/www/api">
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app">
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app/webroot">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
RewriteBase /zm/api
</Directory>
Zoneminder read only user
Right, let’s start with a Zoneminder “read only” user.
In your Zoneminder console, head to Options->User, and smash that “ADD NEW USER” button.
Pretty straight forward:
- Username = YOURPUBLICUSER
- Password = YOURPUBLICPASS
- Confirm Password = YOURPUBLICPASS
- Language
- Enabled = yes
- Stream = View
- Events = None
- Control = None
- Monitors = View
- Groups = None
- System = None
- Max bandwidth = whatever you like
- Restricted monitors = Select the Cameras you want available publicly.
- API Enabled = No
Save that bad boy.
That’s step 1 done 😊
A PHP Proxy script
So at this point you could just jam an image in any web site, using a specially crafted URL:
http://YOUR-ZONEMINDER-CCTV-URL/zm/cgi-bin/nph-zms?monitor=1&user=YOURPUBLICUSER&pass=YOURPUBLICPASS
But, that kinda exposes, well, everything ! Your CCTV url, your readonly user and pass. I dunno, it just doesn’t seem right to me 🤣
So, I’m going to craft a small PHP proxy script which will hide this info from public view.
<?php
// storing this here just for future reference
$streamurl = "http://YOUR-ZONEMINDER-CCTV-URL/zm/cgi-bin/nph-zms?monitor=5&user=YOURPUBLICUSER&pass=YOURPUBLICPASS";
$host = "YOUR-ZONEMINDER-CCTV-URL";
$zmMonitor = "1";
$zmUser = "YOURPUBLICUSER";
$zmPass = "YOURPUBLICPASS";
$requestURI = "/zm/cgi-bin/nph-zms";
$getARGS = $requestURI."?monitor=".$zmMonitor."&user=".$zmUser."&pass=".$zmPass;
set_time_limit(0);
$fp = fsockopen ($host, 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br>\n";
} else {
fputs ($fp, "GET ".$getARGS." HTTP/1.0\r\n\r\n");
while ($str = trim(fgets($fp, 4096)))
header($str);
fpassthru($fp);
fclose($fp);
}
?>
That’s it; save that PHP script as .. I dunno .. zoneminder_stream.php ?
Embed in HTML
Here’s the fun bit .. simple HTML !
<img src="/path/to/zoneminder_stream.php" alt="my stream" />
and here is the working result:
*note: this is a screenshot of my working camera
1 Comment