PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/web/skins/xml/includes/functions.php

https://github.com/eyezm/ZoneMinder
PHP | 455 lines | 428 code | 3 blank | 24 comment | 30 complexity | cebd0cf37ef0e7355bc5f8bddb95c330 MD5 | raw file
  1. <?php
  2. /*
  3. * functions.php is created by Jai Dhar, FPS-Tech, for use with eyeZm
  4. * iPhone application. This is not intended for use with any other applications,
  5. * although source-code is provided under GPL.
  6. *
  7. * For questions, please email support@eyezm.com (http://www.eyezm.com)
  8. *
  9. */
  10. /* These functions are taken from functions.php */
  11. function validInteger( $input )
  12. {
  13. return( preg_replace( '/\D/', '', $input ) );
  14. }
  15. function validString( $input )
  16. {
  17. return( strip_tags( $input ) );
  18. }
  19. /*
  20. * Escape an SQL string, with optional parameters for max. length
  21. */
  22. function escapeSql($str, $maxlen = 0) {
  23. if (!$maxlen) $maxlen = 512;
  24. $string = substr($str, 0, $maxlen);
  25. return (get_magic_quotes_gpc())?mysql_real_escape_string(stripslashes($string)):mysql_real_escape_string($string);
  26. }
  27. /* There appears to be some discrepancy btw. 1.24.1/2 and .3 for EventPaths, to escape them here */
  28. function getEventPathSafe($event)
  29. {
  30. if (ZM_USE_DEEP_STORAGE) {
  31. $ret = ZM_DIR_EVENTS."/".$event['MonitorId'].'/'.strftime( "%y/%m/%d/%H/%M/%S", strtotime($event['StartTime']) );
  32. } else {
  33. $ret = ZM_DIR_EVENTS."/".$event['MonitorId']."/".$event['Id'];
  34. }
  35. return $ret;
  36. }
  37. function updateClientVer()
  38. {
  39. $str = $_SERVER['HTTP_USER_AGENT'];
  40. /* Check if it starts with eyeZm */
  41. if (!strcmp(substr($str, 0, 5),"eyeZm")) {
  42. /* Found eyeZm */
  43. $ver = substr($str, 6);
  44. $verarray = explode(".", $ver);
  45. $_SESSION['vermaj']=$verarray[0];
  46. $_SESSION['vermin']=$verarray[1];
  47. $_SESSION['verbuild']=$verarray[2];
  48. }
  49. logXml("(".$_SERVER['REMOTE_ADDR'].") GET: ".$_SERVER['REQUEST_URI']." - eyeZm ".getClientVerMaj().".".getClientVerMin());
  50. }
  51. function getClientVerMaj()
  52. {
  53. if (isset($_SESSION['vermaj'])) return $_SESSION['vermaj'];
  54. return "0";
  55. }
  56. function getClientVerMin()
  57. {
  58. if (isset($_SESSION['vermin'])) return $_SESSION['vermin'];
  59. return "0";
  60. }
  61. function requireVer($maj, $min)
  62. {
  63. if (getClientVerMaj() > $maj) return 1;
  64. if ((getClientVerMaj() == $maj) && (getClientVerMin() >= $min)) return 1;
  65. return 0;
  66. }
  67. function logXmlErr($str)
  68. {
  69. logXml($str, 1);
  70. }
  71. function logXml($str, $err = 0)
  72. {
  73. if (!defined("ZM_EYEZM_DEBUG")) {
  74. /* Check session variable */
  75. if (isset($_SESSION['xml_debug'])) define("ZM_EYEZM_DEBUG", $_SESSION['xml_debug']);
  76. else define ("ZM_EYEZM_DEBUG", "0");
  77. }
  78. if (!defined("ZM_EYEZM_LOG_TO_FILE")) {
  79. /* Check session variable */
  80. if (isset($_SESSION['xml_log_to_file'])) define("ZM_EYEZM_LOG_TO_FILE", $_SESSION['xml_log_to_file']);
  81. else define ("ZM_EYEZM_LOG_TO_FILE", "1");
  82. }
  83. if (!defined("ZM_EYEZM_LOG_FILE")) {
  84. /* Check session variable */
  85. if (isset($_SESSION['xml_log_file'])) define("ZM_EYEZM_LOG_FILE", $_SESSION['xml_log_file']);
  86. else define ("ZM_EYEZM_LOG_FILE", "/tmp/zm_xml.log");
  87. }
  88. /* Only log if debug is enabled */
  89. if (ZM_EYEZM_DEBUG == 0) return;
  90. /* Logging is enabled, set log string */
  91. $logstr = "XML_LOG (".($err?"ERROR":"NOTICE")."): ".$str.(ZM_EYEZM_LOG_TO_FILE?"\n":"");
  92. if (ZM_EYEZM_LOG_TO_FILE) {
  93. error_log("[".date("r")."] ".$logstr, 3, ZM_EYEZM_LOG_FILE);
  94. } else {
  95. error_log($logstr);
  96. }
  97. }
  98. /* Returns defval if varname is not set, otherwise return varname */
  99. function getset($varname, $defval)
  100. {
  101. if (isset($_GET[$varname])) return $_GET[$varname];
  102. return $defval;
  103. }
  104. function xml_header()
  105. {
  106. header ("content-type: text/xml");
  107. echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  108. }
  109. function xml_tag_val($tag, $val)
  110. {
  111. echo "<".$tag.">".$val."</".$tag.">";
  112. }
  113. function xml_tag_sec($tag, $open)
  114. {
  115. if ($open) $tok = "<";
  116. else $tok = "</";
  117. echo $tok.$tag.">";
  118. }
  119. function xhtmlHeaders( $file, $title )
  120. {
  121. ?>
  122. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  123. <html xmlns="http://www.w3.org/1999/xhtml">
  124. <head>
  125. <style type="text/css">
  126. body {
  127. border: 0px solid;
  128. margin: 0px;
  129. padding: 0px;
  130. }
  131. </style>
  132. <script type="text/javascript">
  133. </script>
  134. </head>
  135. <?php
  136. }
  137. /** Returns whether necessary components for H264 streaming
  138. * are present */
  139. function canStream264($sup = 0) {
  140. if (!ffmpegSupportsCodec("libx264")) {
  141. if (!$sup) logXmlErr("FFMPEG not installed, accessible in path/ZM_PATH_FFMPEG, or doesn't support libx264");
  142. return FALSE;
  143. }
  144. /* Make sure segmenter exists */
  145. if (!exeExists(shell_exec("which segmenter"))) {
  146. if (!$sup) logXmlErr("HTTP segmenter not installed or not accessible in path");
  147. return FALSE;
  148. }
  149. /* Check for zmstreamer */
  150. if (!exeExists(shell_exec("which zmstreamer"))) {
  151. if (!$sup) logXmlErr("ZMSTREAMER not installed or not accessible in path");
  152. return FALSE;
  153. }
  154. return TRUE;
  155. }
  156. /* Returns the path of ffmpeg by using define */
  157. function getFfmpegPath()
  158. {
  159. if (defined("ZM_PATH_FFMPEG")) {
  160. return ZM_PATH_FFMPEG;
  161. } else {
  162. /* Not defined, get it from using 'which' */
  163. return shell_exec("which ffmpeg");
  164. }
  165. }
  166. /* Returns whether ffmpeg supports a given codec. Takes into account
  167. * whether FFMPEG exists or not */
  168. function ffmpegSupportsCodec($codec)
  169. {
  170. if (!ffmpegExists()) return FALSE;
  171. /* FFMPEG exists */
  172. if (preg_match("/\b".$codec."\b/", shell_exec(getFfmpegPath()." -codecs 2> /dev/null")) > 0) {
  173. /* More than one match */
  174. return TRUE;
  175. } else {
  176. /* Check -formats tag also if we fail -codecs */
  177. if (preg_match("/\b".$codec."\b/", shell_exec(getFfmpegPath()." -formats 2> /dev/null")) > 0) return TRUE;
  178. return FALSE;
  179. }
  180. }
  181. function exeExists($exepath)
  182. {
  183. $path = trim($exepath);
  184. return (file_exists($path) && is_readable($path) && ($path != ""));
  185. }
  186. /* Returns whether ffmpeg exists or not */
  187. function ffmpegExists()
  188. {
  189. return exeExists(getFfmpegPath());
  190. }
  191. /* Returns with PHP-GD exists */
  192. function gdExists()
  193. {
  194. if (extension_loaded('gd') && function_exists('gd_info')) {
  195. return TRUE;
  196. }
  197. return FALSE;
  198. }
  199. function getFfmpeg264FoutParms($br, $fout)
  200. {
  201. $ffparms = "-analyzeduration 0 -acodec copy";
  202. $ffparms .= " -vcodec libx264 -b ".$br;
  203. $ffparms .= " -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8";
  204. $ffparms .= " -subq 5 -trellis 1 -refs 1 -coder 0 -me_range 16 -keyint_min 25";
  205. $ffparms .= " -sc_threshold 40 -i_qfactor 0.71 -bt 16k";
  206. $ffparms .= " -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6";
  207. $ffparms .= " -qmin 10 -qmax 51 -qdiff 4 -level 30";
  208. $ffparms .= " -g 30 -analyzeduration 0 -async 2 ".$fout." 2> /dev/null";
  209. return $ffparms;
  210. }
  211. /** Return FFMPEG parameters for H264 streaming */
  212. function getFfmpeg264Str($width, $height, $br, $fin, $fout)
  213. {
  214. $ffparms = getFfmpeg264FoutParms($br, $fout);
  215. $ffstr = getFfmpegPath()." -t ".ZM_EYEZM_H264_MAX_DURATION." -analyzeduration 0 -i ";
  216. $ffstr .= $fin." -f mpegts ".$ffparms;
  217. return $ffstr;
  218. }
  219. /** Returns true when monitor exists */
  220. function isMonitor($monitor)
  221. {
  222. $query = "select Id from Monitors where Id = ".$monitor;
  223. $res = dbFetchOne(escapeSql($query));
  224. if ($res) return TRUE;
  225. logXml("Monitor ID ".$monitor." does not exist");
  226. return FALSE;
  227. }
  228. /** Returns the width and height of a monitor */
  229. function getMonitorDims($monitor)
  230. {
  231. $query = "select Width,Height from Monitors where Id = ".$monitor;
  232. $res = dbFetchOne(escapeSql($query));
  233. return $res;
  234. }
  235. /** Returns the temp directory for H264 encoding */
  236. function getTempDir()
  237. {
  238. /* Assume that the directory structure is <base>/skins/xml/views */
  239. return dirname(__FILE__)."/../../../temp";
  240. }
  241. /** Returns the name of the m3u8 playlist based on monitor */
  242. function m3u8fname($monitor) {
  243. return "stream_".$monitor.".m3u8";
  244. }
  245. /** Erases the M3u8 and TS file names for a given monitor */
  246. function eraseH264Files($monitor) {
  247. /** NOTE: This command executes an 'rm' command, so $monitor parameter
  248. * should be properly validated before executing */
  249. /* Remove wdir/.m3u8 and wdir/sample_<mon>*.ts */
  250. shell_exec("rm -f ".getTempDir()."/".m3u8fname($monitor)." ".getTempDir()."/sample_".$monitor."*.ts");
  251. }
  252. function kill264proc($monitor) {
  253. /** NOTE: This command executes an 'kill' command, so $monitor parameter
  254. * should be properly validated before executing */
  255. $pid = trim(shell_exec("pgrep -f -x \"zmstreamer -m ".$monitor."\""));
  256. if ($pid == "") {
  257. logXml("No PID found for ZMStreamer to kill");
  258. } else {
  259. shell_exec("kill -9 ".$pid);
  260. logXml("Killed process ".$pid." for Monitor ".$monitor);
  261. }
  262. }
  263. /** Return the command-line shell function to setup H264 stream */
  264. function stream264fn ($mid, $width, $height, $br) {
  265. $cdir = "./temp";
  266. $zmstrm = "zmstreamer -m ".$mid." 2> /dev/null";
  267. $ffstr = getFfmpeg264Str($width, $height, $br, "-", "-");
  268. $seg = "segmenter - ".ZM_EYEZM_SEG_DURATION." ".$cdir."/sample_".$mid." ".$cdir."/".m3u8fname($mid)." ../ 2> /dev/null";
  269. $url = $zmstrm . " | ".$ffstr." | " . $seg;
  270. return "nohup ".$url." & echo $!";
  271. }
  272. /** Generate the web-page presented to the viewer when using H264 */
  273. function h264vidHtml($width, $height, $monitor, $br, $thumbsrc) {
  274. function printTermLink() {
  275. $str = "H264 Streaming Launching...<br>Tap to re-load if stream fails";
  276. $str2 = "document.getElementById(\"loaddiv\").innerHTML = \"".$str."\";";
  277. echo $str2;
  278. }
  279. $ajaxUrl = "?view=actions&action=spawn264&&monitor=".$monitor."&br=".$br;
  280. /* Call these two directly to bypass server blocking issues */
  281. $ajax2Url = "./skins/xml/views/actions.php?action=chk264&monitor=".$monitor;
  282. $ajax2Url .= "&timeout=".ZM_EYEZM_H264_TIMEOUT;
  283. $ajax3Url = "./skins/xml/views/actions.php?action=kill264&monitor=".$monitor;
  284. ?>
  285. <html>
  286. <head>
  287. <script type="text/javascript">
  288. /* Called when paused or done is pressed */
  289. function vidAbort() {
  290. document.getElementById('viddiv').style.display = 'none';
  291. var pElement = document.getElementsByTagName('video')[0];
  292. var ajaxKill = new AjaxConnection("<?php echo $ajax3Url;?>");
  293. ajaxKill.connect("cbKilled");
  294. pElement.stop();
  295. pElement.src="";
  296. }
  297. function reloadStreamImage() {
  298. var obj = document.getElementById('liveStream');
  299. var src = obj.src;
  300. var date = new Date();
  301. obj.src = src + '&vrand=' + date.getTime();
  302. return false;
  303. }
  304. /* Callback when spawn264 process is ended */
  305. function cbVidLoad()
  306. {
  307. reloadStreamImage();
  308. <?php
  309. printTermLink();
  310. ?>
  311. }
  312. function vidLoaded() {
  313. window.setTimeout("startVid()", 500);
  314. }
  315. function bindListeners()
  316. {
  317. var pElement = document.getElementsByTagName('video')[0];
  318. /* Bind abort */
  319. pElement.addEventListener('abort', vidAbort, false);
  320. pElement.addEventListener('done', vidAbort, false);
  321. pElement.addEventListener('ended', vidAbort, false);
  322. pElement.addEventListener('pause', vidAbort, false);
  323. pElement.addEventListener('loadstart', vidLoaded, false);
  324. }
  325. /* Callback when kill264 process is ended */
  326. function cbKilled()
  327. {
  328. <?php printTermLink(); ?>
  329. }
  330. /* Called after an interval from cbFileExists() */
  331. function loadVid()
  332. {
  333. var pElement = document.getElementById("vidcontainer");
  334. <?php
  335. echo "pElement.src=\"./temp/".m3u8fname($monitor)."\"\n";
  336. ?>
  337. pElement.load();
  338. }
  339. function startVid()
  340. {
  341. document.getElementById('viddiv').style.display = 'block';
  342. var pElement = document.getElementById("vidcontainer");
  343. pElement.play();
  344. }
  345. /* Callback when stream is active and ready to be played */
  346. function cbFileExists()
  347. {
  348. window.setTimeout("loadVid()", 500);
  349. }
  350. /* On-load triggers two requests immediately: spawn264 and chk264 */
  351. window.onload = function() {
  352. bindListeners();
  353. var ajax1 = new AjaxConnection("<?php echo "$ajaxUrl";?>");
  354. var ajax2 = new AjaxConnection("<?php echo "$ajax2Url";?>");
  355. ajax1.connect("cbVidLoad");
  356. /* Don't initiate file-exists since eyeZm will */
  357. /*ajax2.connect("cbFileExists");*/
  358. }
  359. function AjaxConnection(url) {
  360. this.connect = connect;
  361. this.url = url;
  362. }
  363. function connect(return_func) {
  364. this.x = new XMLHttpRequest();
  365. this.x.open("GET", this.url, true);
  366. var self = this;
  367. this.x.onreadystatechange = function() {
  368. if (self.x.readyState != 4)
  369. return;
  370. eval(return_func + '()');
  371. delete self.x;
  372. }
  373. this.x.send(null);
  374. }
  375. </script>
  376. <style type="text/css">
  377. body {
  378. border: 0px solid;
  379. margin: 0px;
  380. padding: 0px;
  381. background-color: black;
  382. width: <?php echo $width ?>px;
  383. height: <?php echo $height ?>px;
  384. }
  385. .textcl {
  386. text-align: center;
  387. font-family: Arial;
  388. font-size: larger;
  389. width: 100%;
  390. <?php echo "padding-top: ".(($height/2)-100)."px;"; ?>
  391. <?php echo "padding-bottom: ".(($height/2)-100)."px;"; ?>
  392. z-index: 2;
  393. position: absolute;
  394. top: 0px;
  395. left: 0px;
  396. height: 100%;
  397. }
  398. .textcl2 {
  399. width: auto;
  400. height: auto;
  401. background-color: black;
  402. padding: 5px 5px;
  403. margin-left: 10px;
  404. margin-right: 10px;
  405. opacity: 0.7;
  406. }
  407. .textcl3 {
  408. width: auto;
  409. height: auto;
  410. padding: 2px 2px;
  411. margin: auto;
  412. color: white;
  413. }
  414. .imgdiv {
  415. position: absolute;
  416. padding: 0px;
  417. background-color: black;
  418. top: 0px;
  419. left: 0px;
  420. margin: 0px;
  421. width: <?php echo $width ?>px;
  422. height: <?php echo $height ?>px;
  423. z-index: 1;
  424. opacity: 0.7;
  425. }
  426. </style>
  427. </head>
  428. <body>
  429. <div id="viddiv" style="display: none;">
  430. <?php
  431. echo "<video id=\"vidcontainer\" width='".$width."' height='".$height."' />\n";
  432. ?>
  433. </div>
  434. <div id="loaddiv2" class="textcl"><div id="loaddiv3" class="textcl2">
  435. <div id="loaddiv" class="textcl3">
  436. Initializing H264 Stream (<?php echo($br); ?>)...<br>
  437. <span style="font-size: small;"><i>This may take a few seconds</i></span>
  438. </div>
  439. </div></div>
  440. <div class="imgdiv" id="imagediv">
  441. <?php outputImageStream("liveStream", $thumbsrc, $width, $height, "stream"); ?>
  442. </div>
  443. </body>
  444. </html>
  445. <?php
  446. }
  447. ?>