api.onvif.php 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. <?php
  2. /**
  3. * @author Lorenzo Toscano <lorenzo.toscano@gmail.com>
  4. * @version 1.0
  5. * @desc A simple class to help you in developing an ONVIF compliant client
  6. * FIX by KuroNeko 03.03.2017
  7. * getBaseUrl() - fixed "baseuri"
  8. * _getProfileData() - added "profilename" and fixed "profiletoken"
  9. * isFault() - added additional check for "Fault" scenario
  10. * discover() - added Onvif WS-Discovery implementation
  11. * getDeviceUri() - fixed "deviceuri"
  12. * setDeviceUri() - fixed "deviceuri"
  13. * setMediaUri() - added MediaUri setter
  14. **/
  15. class Ponvif {
  16. /*
  17. $ipaddress ip address of the NVT device
  18. $username NVT authentication username
  19. $password NVT authentication password
  20. $mediauri media web service uri
  21. $deviceuri core web service uri
  22. $ptzuri ptz web service uri
  23. $baseuri url of the NVT (without service specification)
  24. $onvifversion onvif version supported by the NVT
  25. $deltatime time differential correction (used to synchronize NVC with NVT)
  26. $capabilites response of GetCapabilities
  27. $videosources response of GetVideoSources
  28. $sources array cotaining tokens for further requests
  29. $profiles response of GetProfiles
  30. $proxyhost proxy
  31. $proxyport proxy port
  32. $proxyusername proxy authentication username
  33. $proxypassword proxy authentication password
  34. $lastresponse last soap response
  35. $discoverytimeout WS-Discovery waiting time (sec)
  36. $discoverymcastip WS-Discovery multicast ip address
  37. $discoverymcastport WS-Discovery multicast port
  38. $discoveryhideduplicates WS-Discovery flag to show\hide duplicates via source IP
  39. */
  40. protected $ipaddress = '';
  41. protected $username = '';
  42. protected $password = '';
  43. protected $mediauri = '';
  44. protected $deviceuri = '';
  45. protected $ptzuri = '';
  46. protected $baseuri = '';
  47. protected $onvifversion = array();
  48. protected $deltatime = 0;
  49. protected $capabilities = array();
  50. protected $videosources = array();
  51. protected $sources = array();
  52. protected $profiles = array();
  53. protected $proxyhost = '';
  54. protected $proxyport = '';
  55. protected $proxyusername = '';
  56. protected $proxypassword = '';
  57. protected $lastresponse = '';
  58. protected $intransingent = true;
  59. protected $discoverytimeout = 2;
  60. protected $discoverybindip = '0.0.0.0';
  61. protected $discoverymcastip = '239.255.255.250';
  62. protected $discoverymcastport = 3702;
  63. protected $discoveryhideduplicates = true;
  64. /*
  65. Properties wrappers
  66. */
  67. public function setProxyHost($proxyHost) {
  68. $this->proxyhost = $proxyHost;
  69. }
  70. public function getProxyHost() {
  71. return $this->proxyhost;
  72. }
  73. public function setProxyPort($proxyPort) {
  74. $this->proxyport = $proxyPort;
  75. }
  76. public function getProxyPort() {
  77. return $this->proxyport;
  78. }
  79. public function setProxyUsername($proxyUsername) {
  80. $this->proxyusername = $proxyUsername;
  81. }
  82. public function getProxyUsername() {
  83. return $this->proxyusername;
  84. }
  85. public function setProxyPassword($proxyPassword) {
  86. $this->proxypassword = $proxyPassword;
  87. }
  88. public function getProxyPassword() {
  89. return $this->proxypassword;
  90. }
  91. public function setUsername($username) {
  92. $this->username = $username;
  93. }
  94. public function getUsername() {
  95. return $this->username;
  96. }
  97. public function setPassword($password) {
  98. $this->password = $password;
  99. }
  100. public function getPassword() {
  101. return $this->password;
  102. }
  103. public function getDeviceUri() {
  104. return $this->deviceuri;
  105. }
  106. public function setDeviceUri($deviceuri) {
  107. $this->deviceuri = $deviceuri;
  108. }
  109. public function getIPAddress($ipAddress) {
  110. return $this->ipAddress;
  111. }
  112. public function setIPAddress($ipAddress) {
  113. $this->ipaddress = $ipAddress;
  114. }
  115. public function getSources() {
  116. return $this->sources;
  117. }
  118. public function getMediaUri() {
  119. return $this->mediauri;
  120. }
  121. public function setMediaUri($mediauri) {
  122. $this->mediauri = $mediauri;
  123. }
  124. public function getPTZUri() {
  125. return $this->ptzuri;
  126. }
  127. public function getBaseUrl() {
  128. return $this->baseuri;
  129. }
  130. public function getSupportedVersion() {
  131. return $this->onvifversion;
  132. }
  133. public function getCapabilities() {
  134. return $this->capabilities;
  135. }
  136. public function setBreakOnError($intransingent) {
  137. $this->intransingent = $intransingent;
  138. }
  139. public function getLastResponse() {
  140. return $this->lastresponse;
  141. }
  142. public function setDiscoveryTimeout($discoverytimeout) {
  143. $this->discoverytimeout = $discoverytimeout;
  144. }
  145. public function setDiscoveryBindIp($discoverybindip) {
  146. $this->discoverybindip = $discoverybindip;
  147. }
  148. public function setDiscoveryMcastIp($discoverymcastip) {
  149. $this->discoverymcastip = $discoverymcastip;
  150. }
  151. public function setDiscoveryMcastPort($discoverymcastport) {
  152. $this->discoverymcastport = $discoverymcastport;
  153. }
  154. public function setDiscoveryHideDuplicates($discoveryhideduplicates) {
  155. $this->discoveryhideduplicates = $discoveryhideduplicates;
  156. }
  157. /*
  158. Constructor & Destructor
  159. */
  160. public function __construct() {
  161. // nothing to do
  162. }
  163. public function __destruct() {
  164. // nothing to do
  165. }
  166. /*
  167. WS-Discovery
  168. */
  169. public function discover() {
  170. $result = array();
  171. $timeout = time() + $this->discoverytimeout;
  172. $post_string = '<?xml version="1.0" encoding="UTF-8"?><e:Envelope xmlns:e="http://www.w3.org/2003/05/soap-envelope" xmlns:w="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:dn="http://www.onvif.org/ver10/network/wsdl"><e:Header><w:MessageID>uuid:84ede3de-7dec-11d0-c360-f01234567890</w:MessageID><w:To e:mustUnderstand="true">urn:schemas-xmlsoap-org:ws:2005:04:discovery</w:To><w:Action a:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</w:Action></e:Header><e:Body><d:Probe><d:Types>dn:NetworkVideoTransmitter</d:Types></d:Probe></e:Body></e:Envelope>';
  173. try {
  174. if (FALSE == ($sock = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP))) {
  175. echo ('Create socket error: [' . socket_last_error() . '] ' . socket_strerror(socket_last_error()));
  176. }
  177. if (FALSE == @socket_bind($sock, $this->discoverybindip, rand(20000, 40000))) {
  178. echo ('Bind socket error: [' . socket_last_error() . '] ' . socket_strerror(socket_last_error()));
  179. }
  180. socket_set_option($sock, IPPROTO_IP, MCAST_JOIN_GROUP, array('group' => $this->discoverymcastip));
  181. socket_sendto($sock, $post_string, strlen($post_string), 0, $this->discoverymcastip, $this->discoverymcastport);
  182. socket_set_nonblock($sock);
  183. while (time() < $timeout) {
  184. if (FALSE !== @socket_recvfrom($sock, $response, 9999, 0, $from, $this->discoverymcastport)) {
  185. if ($response != NULL && $response != $post_string) {
  186. $response = $this->_xml2array($response);
  187. if (!$this->isFault($response)) {
  188. $response['Envelope']['Body']['ProbeMatches']['ProbeMatch']['IPAddr'] = $from;
  189. if ($this->discoveryhideduplicates) {
  190. $result[$from] = $response['Envelope']['Body']['ProbeMatches']['ProbeMatch'];
  191. } else {
  192. $result[] = $response['Envelope']['Body']['ProbeMatches']['ProbeMatch'];
  193. }
  194. }
  195. }
  196. }
  197. }
  198. socket_close($sock);
  199. } catch (Exception $e) {
  200. }
  201. sort($result);
  202. return $result;
  203. }
  204. /*
  205. Public functions (basic initialization method and other collaterals)
  206. */
  207. public function initialize() {
  208. if (!$this->mediauri) {
  209. $this->mediauri = 'http://' . $this->ipaddress . '/onvif/device_service';
  210. }
  211. try {
  212. $datetime = $this->core_GetSystemDateAndTime();
  213. $timestamp = mktime(
  214. $datetime['Time']['Hour'],
  215. $datetime['Time']['Minute'],
  216. $datetime['Time']['Second'],
  217. $datetime['Date']['Month'],
  218. $datetime['Date']['Day'],
  219. $datetime['Date']['Year']
  220. );
  221. $this->deltatime = time() - $timestamp - 5;
  222. } catch (Exception $e) {
  223. }
  224. $this->capabilities = $this->core_GetCapabilities();
  225. $onvifVersion = $this->_getOnvifVersion($this->capabilities);
  226. $this->mediauri = $onvifVersion['media'];
  227. $this->deviceuri = $onvifVersion['device'];
  228. $this->ptzuri = $onvifVersion['ptz'];
  229. preg_match("/^http(.*)onvif\//", $this->mediauri, $matches);
  230. $this->baseuri = $matches[0];
  231. $this->onvifversion = array(
  232. 'major' => $onvifVersion['major'],
  233. 'minor' => $onvifVersion['minor']
  234. );
  235. $this->videosources = $this->media_GetVideoSources();
  236. $this->profiles = $this->media_GetProfiles();
  237. $this->sources = $this->_getActiveSources($this->videosources, $this->profiles);
  238. }
  239. public function isFault($response) { // Useful to check if response contains a fault
  240. return array_key_exists('Fault', $response) || array_key_exists('Fault', $response['Envelope']['Body']);
  241. }
  242. /*
  243. Public wrappers for a subset of ONVIF primitives
  244. */
  245. public function core_GetSystemDateAndTime() {
  246. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetSystemDateAndTime xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>';
  247. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  248. if ($this->intransingent) throw new Exception('GetSystemDateAndTime: Communication error');
  249. } else
  250. return $response['Envelope']['Body']['GetSystemDateAndTimeResponse']['SystemDateAndTime']['UTCDateTime'];
  251. }
  252. public function core_GetCapabilities() {
  253. $REQ = $this->_makeToken();
  254. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"><Category>All</Category></GetCapabilities></s:Body></s:Envelope>';
  255. $post_string = str_replace(
  256. array(
  257. "%%USERNAME%%",
  258. "%%PASSWORD%%",
  259. "%%NONCE%%",
  260. "%%CREATED%%"
  261. ),
  262. array(
  263. $REQ['USERNAME'],
  264. $REQ['PASSDIGEST'],
  265. $REQ['NONCE'],
  266. $REQ['TIMESTAMP']
  267. ),
  268. $post_string
  269. );
  270. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  271. if ($this->intransingent) throw new Exception('GetCapabilities: Communication error');
  272. } else
  273. return $response['Envelope']['Body']['GetCapabilitiesResponse']['Capabilities'];
  274. }
  275. public function media_GetVideoSources() {
  276. $REQ = $this->_makeToken();
  277. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetVideoSources xmlns="http://www.onvif.org/ver10/media/wsdl"/></s:Body></s:Envelope>';
  278. $post_string = str_replace(
  279. array(
  280. "%%USERNAME%%",
  281. "%%PASSWORD%%",
  282. "%%NONCE%%",
  283. "%%CREATED%%"
  284. ),
  285. array(
  286. $REQ['USERNAME'],
  287. $REQ['PASSDIGEST'],
  288. $REQ['NONCE'],
  289. $REQ['TIMESTAMP']
  290. ),
  291. $post_string
  292. );
  293. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  294. if ($this->intransingent) throw new Exception('GetVideoSources: Communication error');
  295. } else
  296. return $response['Envelope']['Body']['GetVideoSourcesResponse']['VideoSources'];
  297. }
  298. public function media_GetProfiles() {
  299. $REQ = $this->_makeToken();
  300. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl"/></s:Body></s:Envelope>';
  301. $post_string = str_replace(
  302. array(
  303. "%%USERNAME%%",
  304. "%%PASSWORD%%",
  305. "%%NONCE%%",
  306. "%%CREATED%%"
  307. ),
  308. array(
  309. $REQ['USERNAME'],
  310. $REQ['PASSDIGEST'],
  311. $REQ['NONCE'],
  312. $REQ['TIMESTAMP']
  313. ),
  314. $post_string
  315. );
  316. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  317. if ($this->intransingent) throw new Exception('GetProfiles: Communication error');
  318. } else
  319. return $response['Envelope']['Body']['GetProfilesResponse']['Profiles'];
  320. }
  321. public function media_GetServices() {
  322. $REQ = $this->_makeToken();
  323. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetServices xmlns="http://www.onvif.org/ver10/device/wsdl"><IncludeCapability>false</IncludeCapability></GetServices></s:Body></s:Envelope>';
  324. $post_string = str_replace(
  325. array(
  326. "%%USERNAME%%",
  327. "%%PASSWORD%%",
  328. "%%NONCE%%",
  329. "%%CREATED%%"
  330. ),
  331. array(
  332. $REQ['USERNAME'],
  333. $REQ['PASSDIGEST'],
  334. $REQ['NONCE'],
  335. $REQ['TIMESTAMP']
  336. ),
  337. $post_string
  338. );
  339. if ($this->isFault($this->_send_request($this->mediauri, $post_string))) {
  340. if ($this->intransingent) throw new Exception('GetServices: Communication error');
  341. }
  342. }
  343. public function core_GetDeviceInformation() {
  344. $REQ = $this->_makeToken();
  345. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetDeviceInformation xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>';
  346. $post_string = str_replace(
  347. array(
  348. "%%USERNAME%%",
  349. "%%PASSWORD%%",
  350. "%%NONCE%%",
  351. "%%CREATED%%"
  352. ),
  353. array(
  354. $REQ['USERNAME'],
  355. $REQ['PASSDIGEST'],
  356. $REQ['NONCE'],
  357. $REQ['TIMESTAMP']
  358. ),
  359. $post_string
  360. );
  361. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  362. if ($this->intransingent) throw new Exception('GetDeviceInformation: Communication error');
  363. } else
  364. return $response['Envelope']['Body']['GetDeviceInformationResponse'];
  365. }
  366. public function media_GetStreamUri($profileToken, $stream = "RTP-Unicast", $protocol = "RTSP") {
  367. $REQ = $this->_makeToken();
  368. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetStreamUri xmlns="http://www.onvif.org/ver10/media/wsdl"><StreamSetup><Stream xmlns="http://www.onvif.org/ver10/schema">%%STREAM%%</Stream><Transport xmlns="http://www.onvif.org/ver10/schema"><Protocol>%%PROTOCOL%%</Protocol></Transport></StreamSetup><ProfileToken>%%PROFILETOKEN%%</ProfileToken></GetStreamUri></s:Body></s:Envelope>';
  369. $post_string = str_replace(
  370. array(
  371. "%%USERNAME%%",
  372. "%%PASSWORD%%",
  373. "%%NONCE%%",
  374. "%%CREATED%%",
  375. "%%PROFILETOKEN%%",
  376. "%%STREAM%%",
  377. "%%PROTOCOL%%"
  378. ),
  379. array(
  380. $REQ['USERNAME'],
  381. $REQ['PASSDIGEST'],
  382. $REQ['NONCE'],
  383. $REQ['TIMESTAMP'],
  384. $profileToken,
  385. $stream,
  386. $protocol
  387. ),
  388. $post_string
  389. );
  390. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  391. if ($this->intransingent) throw new Exception('GetStreamUri: Communication error');
  392. } else
  393. return $response['Envelope']['Body']['GetStreamUriResponse']['MediaUri']['Uri'];
  394. }
  395. public function media_GetSnapshotUri($profileToken) {
  396. $REQ = $this->_makeToken();
  397. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetSnapshotUri xmlns="http://www.onvif.org/ver10/media/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken></GetSnapshotUri></s:Body></s:Envelope>';
  398. $post_string = str_replace(
  399. array(
  400. "%%USERNAME%%",
  401. "%%PASSWORD%%",
  402. "%%NONCE%%",
  403. "%%CREATED%%",
  404. "%%PROFILETOKEN%%"
  405. ),
  406. array(
  407. $REQ['USERNAME'],
  408. $REQ['PASSDIGEST'],
  409. $REQ['NONCE'],
  410. $REQ['TIMESTAMP'],
  411. $profileToken
  412. ),
  413. $post_string
  414. );
  415. if ($this->isFault($response = $this->_send_request($this->mediauri, $post_string))) {
  416. if ($this->intransingent) throw new Exception('GetSnapshotUri: Communication error');
  417. var_dump($response);
  418. } else
  419. return $response['Envelope']['Body']['GetSnapshotUriResponse']['MediaUri']['Uri'];
  420. }
  421. public function ptz_GetPresets($profileToken) {
  422. if ($this->ptzuri == '') return array();
  423. $REQ = $this->_makeToken();
  424. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetPresets xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken></GetPresets></s:Body></s:Envelope>';
  425. $post_string = str_replace(
  426. array(
  427. "%%USERNAME%%",
  428. "%%PASSWORD%%",
  429. "%%NONCE%%",
  430. "%%CREATED%%",
  431. "%%PROFILETOKEN%%"
  432. ),
  433. array(
  434. $REQ['USERNAME'],
  435. $REQ['PASSDIGEST'],
  436. $REQ['NONCE'],
  437. $REQ['TIMESTAMP'],
  438. $profileToken
  439. ),
  440. $post_string
  441. );
  442. if ($this->isFault($response = $this->_send_request($this->ptzuri, $post_string))) {
  443. if ($this->intransingent) throw new Exception('GetPresets: Communication error');
  444. } else {
  445. $getpresetsresponse = $response['Envelope']['Body']['GetPresetsResponse']['Preset'];
  446. $presets = array();
  447. foreach ($getpresetsresponse as $preset) {
  448. $presets[] = array(
  449. 'Token' => $preset['@attributes']['token'],
  450. 'Name' => $preset['Name'],
  451. 'PTZPosition' => $preset['PTZPosition']
  452. );
  453. }
  454. return $presets;
  455. }
  456. }
  457. public function ptz_GetNode($ptzNodeToken) {
  458. if ($this->ptzuri == '') return array();
  459. $REQ = $this->_makeToken();
  460. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetNode xmlns="http://www.onvif.org/ver20/ptz/wsdl"><NodeToken>%%NODETOKEN%%</NodeToken></GetNode></s:Body></s:Envelope>';
  461. $post_string = str_replace(
  462. array(
  463. "%%USERNAME%%",
  464. "%%PASSWORD%%",
  465. "%%NONCE%%",
  466. "%%CREATED%%",
  467. "%%NODETOKEN%%"
  468. ),
  469. array(
  470. $REQ['USERNAME'],
  471. $REQ['PASSDIGEST'],
  472. $REQ['NONCE'],
  473. $REQ['TIMESTAMP'],
  474. $ptzNodeToken
  475. ),
  476. $post_string
  477. );
  478. if ($this->isFault($response = $this->_send_request($this->ptzuri, $post_string))) {
  479. if ($this->intransingent) throw new Exception('GetNode: Communication error');
  480. } else
  481. return $response['Envelope']['Body']['GetNodeResponse'];
  482. }
  483. public function ptz_GotoPreset($profileToken, $presetToken, $speed_pantilt_x, $speed_pantilt_y, $speed_zoom_x) {
  484. if ($this->ptzuri == '') return array();
  485. $REQ = $this->_makeToken();
  486. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GotoPreset xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><PresetToken>%%PRESETTOKEN%%</PresetToken><Speed><PanTilt x="%%SPEEDPANTILTX%%" y="%%SPEEDPANTILTY%%" xmlns="http://www.onvif.org/ver10/schema"/><Zoom x="%%SPEEDZOOMX%%" xmlns="http://www.onvif.org/ver10/schema"/></Speed></GotoPreset></s:Body></s:Envelope>';
  487. $post_string = str_replace(
  488. array(
  489. "%%USERNAME%%",
  490. "%%PASSWORD%%",
  491. "%%NONCE%%",
  492. "%%CREATED%%",
  493. "%%PROFILETOKEN%%",
  494. "%%PRESETTOKEN%%",
  495. "%%SPEEDPANTILTX%%",
  496. "%%SPEEDPANTILTY%%",
  497. "%%SPEEDZOOMX%%"
  498. ),
  499. array(
  500. $REQ['USERNAME'],
  501. $REQ['PASSDIGEST'],
  502. $REQ['NONCE'],
  503. $REQ['TIMESTAMP'],
  504. $profileToken,
  505. $presetToken,
  506. $speed_pantilt_x,
  507. $speed_pantilt_y,
  508. $speed_zoom_x
  509. ),
  510. $post_string
  511. );
  512. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  513. if ($this->intransingent) throw new Exception('GotoPreset: Communication error');
  514. }
  515. }
  516. public function ptz_RemovePreset($profileToken, $presetToken) {
  517. if ($this->ptzuri == '') return array();
  518. $REQ = $this->_makeToken();
  519. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><RemovePreset xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><PresetToken>%%PRESETTOKEN%%</PresetToken></RemovePreset></s:Body></s:Envelope>';
  520. $post_string = str_replace(
  521. array(
  522. "%%USERNAME%%",
  523. "%%PASSWORD%%",
  524. "%%NONCE%%",
  525. "%%CREATED%%",
  526. "%%PROFILETOKEN%%",
  527. "%%PRESETTOKEN%%"
  528. ),
  529. array(
  530. $REQ['USERNAME'],
  531. $REQ['PASSDIGEST'],
  532. $REQ['NONCE'],
  533. $REQ['TIMESTAMP'],
  534. $profileToken,
  535. $presetToken
  536. ),
  537. $post_string
  538. );
  539. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  540. if ($this->intransingent) throw new Exception('RemovePreset: Communication error');
  541. }
  542. }
  543. public function ptz_SetPreset($profileToken, $presetName) {
  544. if ($this->ptzuri == '') return array();
  545. $REQ = $this->_makeToken();
  546. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetPreset xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><PresetName>%%PRESETNAME%%</PresetName></SetPreset></s:Body></s:Envelope>';
  547. $post_string = str_replace(
  548. array(
  549. "%%USERNAME%%",
  550. "%%PASSWORD%%",
  551. "%%NONCE%%",
  552. "%%CREATED%%",
  553. "%%PROFILETOKEN%%",
  554. "%%PRESETNAME%%"
  555. ),
  556. array(
  557. $REQ['USERNAME'],
  558. $REQ['PASSDIGEST'],
  559. $REQ['NONCE'],
  560. $REQ['TIMESTAMP'],
  561. $profileToken,
  562. $presetName
  563. ),
  564. $post_string
  565. );
  566. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  567. if ($this->intransingent) throw new Exception('SetPreset: Communication error');
  568. }
  569. }
  570. public function ptz_RelativeMove($profileToken, $translation_pantilt_x, $translation_pantilt_y, $speed_pantilt_x, $speed_pantilt_y) {
  571. if ($this->ptzuri == '') return array();
  572. $REQ = $this->_makeToken();
  573. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><RelativeMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><Translation><PanTilt x="%%TRANSLATIONPANTILTX%%" y="%%TRANSLATIONPANTILTY%%" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/></Translation><Speed><PanTilt x="%%SPEEDPANTILTX%%" y="%%SPEEDPANTILTY%%" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace" xmlns="http://www.onvif.org/ver10/schema"/></Speed></RelativeMove></s:Body></s:Envelope>';
  574. $post_string = str_replace(
  575. array(
  576. "%%USERNAME%%",
  577. "%%PASSWORD%%",
  578. "%%NONCE%%",
  579. "%%CREATED%%",
  580. "%%PROFILETOKEN%%",
  581. "%%TRANSLATIONPANTILTX%%",
  582. "%%TRANSLATIONPANTILTY%%",
  583. "%%SPEEDPANTILTX%%",
  584. "%%SPEEDPANTILTY%%"
  585. ),
  586. array(
  587. $REQ['USERNAME'],
  588. $REQ['PASSDIGEST'],
  589. $REQ['NONCE'],
  590. $REQ['TIMESTAMP'],
  591. $profileToken,
  592. $translation_pantilt_x,
  593. $translation_pantilt_y,
  594. $speed_pantilt_x,
  595. $speed_pantilt_y
  596. ),
  597. $post_string
  598. );
  599. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  600. if ($this->intransingent) throw new Exception('RelativeMove: Communication error');
  601. }
  602. }
  603. public function ptz_RelativeMoveZoom($profileToken, $zoom, $speedZoom) {
  604. if ($this->ptzuri == '') return array();
  605. $REQ = $this->_makeToken();
  606. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><RelativeMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><Translation><Zoom x="%%ZOOM%%" space="http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/></Translation><Speed><Zoom x="%%SPEEDZOOM%%" space="http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace" xmlns="http://www.onvif.org/ver10/schema"/></Speed></RelativeMove></s:Body></s:Envelope>';
  607. $post_string = str_replace(
  608. array(
  609. "%%USERNAME%%",
  610. "%%PASSWORD%%",
  611. "%%NONCE%%",
  612. "%%CREATED%%",
  613. "%%PROFILETOKEN%%",
  614. "%%SPEEDZOOM%%",
  615. "%%ZOOM%%"
  616. ),
  617. array(
  618. $REQ['USERNAME'],
  619. $REQ['PASSDIGEST'],
  620. $REQ['NONCE'],
  621. $REQ['TIMESTAMP'],
  622. $profileToken,
  623. $speedZoom,
  624. $zoom
  625. ),
  626. $post_string
  627. );
  628. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  629. if ($this->intransingent) throw new Exception('RelativeMoveZoom: Communication error');
  630. }
  631. }
  632. public function ptz_AbsoluteMove($profileToken, $position_pantilt_x, $position_pantilt_y, $zoom) {
  633. if ($this->ptzuri == '') return array();
  634. $REQ = $this->_makeToken();
  635. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><AbsoluteMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><Position><PanTilt x="%%POSITIONPANTILTX%%" y="%%POSITIONPANTILTY%%" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/><Zoom x="%%ZOOM%%" space="http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/></Position></AbsoluteMove></s:Body></s:Envelope>';
  636. $post_string = str_replace(
  637. array(
  638. "%%USERNAME%%",
  639. "%%PASSWORD%%",
  640. "%%NONCE%%",
  641. "%%CREATED%%",
  642. "%%PROFILETOKEN%%",
  643. "%%POSITIONPANTILTX%%",
  644. "%%POSITIONPANTILTY%%",
  645. "%%ZOOM%%"
  646. ),
  647. array(
  648. $REQ['USERNAME'],
  649. $REQ['PASSDIGEST'],
  650. $REQ['NONCE'],
  651. $REQ['TIMESTAMP'],
  652. $profileToken,
  653. $position_pantilt_x,
  654. $position_pantilt_y,
  655. $zoom
  656. ),
  657. $post_string
  658. );
  659. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  660. if ($this->intransingent) throw new Exception('AbsoluteMove: Communication error');
  661. }
  662. }
  663. public function ptz_ContinuousMove($profileToken, $velocity_pantilt_x, $velocity_pantilt_y) {
  664. if ($this->ptzuri == '') return array();
  665. $REQ = $this->_makeToken();
  666. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><Velocity><PanTilt x="%%VELOCITYPANTILTX%%" y="%%VELOCITYPANTILTY%%" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>';
  667. $post_string = str_replace(
  668. array(
  669. "%%USERNAME%%",
  670. "%%PASSWORD%%",
  671. "%%NONCE%%",
  672. "%%CREATED%%",
  673. "%%PROFILETOKEN%%",
  674. "%%VELOCITYPANTILTX%%",
  675. "%%VELOCITYPANTILTY%%"
  676. ),
  677. array(
  678. $REQ['USERNAME'],
  679. $REQ['PASSDIGEST'],
  680. $REQ['NONCE'],
  681. $REQ['TIMESTAMP'],
  682. $profileToken,
  683. $velocity_pantilt_x,
  684. $velocity_pantilt_y
  685. ),
  686. $post_string
  687. );
  688. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  689. if ($this->intransingent) throw new Exception('ContinuousMove: Communication error');
  690. }
  691. }
  692. public function ptz_ContinuousMoveZoom($profileToken, $zoom) {
  693. if ($this->ptzuri == '') return array();
  694. $REQ = $this->_makeToken();
  695. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><Velocity><Zoom x="%%ZOOM%%" space="http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>';
  696. $post_string = str_replace(
  697. array(
  698. "%%USERNAME%%",
  699. "%%PASSWORD%%",
  700. "%%NONCE%%",
  701. "%%CREATED%%",
  702. "%%PROFILETOKEN%%",
  703. "%%ZOOM%%"
  704. ),
  705. array(
  706. $REQ['USERNAME'],
  707. $REQ['PASSDIGEST'],
  708. $REQ['NONCE'],
  709. $REQ['TIMESTAMP'],
  710. $profileToken,
  711. $zoom
  712. ),
  713. $post_string
  714. );
  715. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  716. if ($this->intransingent) throw new Exception('ContinuousMoveZoom: Communication error');
  717. }
  718. }
  719. public function ptz_Stop($profileToken, $pantilt, $zoom) {
  720. if ($this->ptzuri == '') return array();
  721. $REQ = $this->_makeToken();
  722. $post_string = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>%%USERNAME%%</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%%PASSWORD%%</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%%NONCE%%</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%%CREATED%%</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Stop xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>%%PROFILETOKEN%%</ProfileToken><PanTilt>%%PANTILT%%</PanTilt><Zoom>%%ZOOM%%</Zoom></Stop></s:Body></s:Envelope>';
  723. $post_string = str_replace(
  724. array(
  725. "%%USERNAME%%",
  726. "%%PASSWORD%%",
  727. "%%NONCE%%",
  728. "%%CREATED%%",
  729. "%%PROFILETOKEN%%",
  730. "%%PANTILT%%",
  731. "%%ZOOM%%"
  732. ),
  733. array(
  734. $REQ['USERNAME'],
  735. $REQ['PASSDIGEST'],
  736. $REQ['NONCE'],
  737. $REQ['TIMESTAMP'],
  738. $profileToken,
  739. $pantilt,
  740. $zoom
  741. ),
  742. $post_string
  743. );
  744. if ($this->isFault($this->_send_request($this->ptzuri, $post_string))) {
  745. if ($this->intransingent) throw new Exception('Stop: Communication error');
  746. }
  747. }
  748. /*
  749. Internal functions
  750. */
  751. protected function _makeToken() {
  752. $timestamp = time() - $this->deltatime;
  753. return $this->_passwordDigest($this->username, $this->password, date('Y-m-d\TH:i:s.000\Z', $timestamp));
  754. }
  755. protected function _getOnvifVersion($capabilities) {
  756. $version = array();
  757. if (isset($capabilities['Device']['System']['SupportedVersions']['Major'])) {
  758. // NVT supports a specific onvif version
  759. $version['major'] = $capabilities['Device']['System']['SupportedVersions']['Major'];
  760. $version['minor'] = $capabilities['Device']['System']['SupportedVersions']['Minor'];
  761. } else {
  762. // NVT supports more onvif versions
  763. $currentma = 0;
  764. $currentmi = 0;
  765. foreach ($capabilities['Device']['System']['SupportedVersions'] as $cver) {
  766. if ($cver['Major'] > $currentma) {
  767. $currentma = $cver['Major'];
  768. $currentmi = $cver['Minor'];
  769. }
  770. }
  771. $version['major'] = $currentma;
  772. $version['minor'] = $currentmi;
  773. }
  774. $version['media'] = $capabilities['Media']['XAddr'];
  775. $version['device'] = $capabilities['Device']['XAddr'];
  776. $version['event'] = $capabilities['Events']['XAddr'];
  777. if (isset($capabilities['PTZ']['XAddr'])) $version['ptz'] = $capabilities['PTZ']['XAddr'];
  778. else $version['ptz'] = '';
  779. return $version;
  780. }
  781. protected function _getActiveSources($videoSources, $profiles) {
  782. $sources = array();
  783. if (isset($videoSources['@attributes'])) {
  784. // NVT is a camera
  785. $sources[0]['sourcetoken'] = $videoSources['@attributes']['token'];
  786. $this->_getProfileData($sources, 0, $profiles);
  787. } else {
  788. // NVT is an encoder
  789. for ($i = 0; $i < count($videoSources); $i++) {
  790. if (strtolower($videoSources[$i]['@attributes']['SignalActive']) == 'true') {
  791. $sources[$i]['sourcetoken'] = $videoSources[$i]['@attributes']['token'];
  792. $this->_getProfileData($sources, $i, $profiles);
  793. }
  794. } // for
  795. }
  796. return $sources;
  797. }
  798. protected function _getProfileData(&$sources, $i, $profiles) {
  799. $inprofile = 0;
  800. for ($y = 0; $y < count($profiles); $y++) {
  801. if ($profiles[$y]['VideoSourceConfiguration']['SourceToken'] == $sources[$i]['sourcetoken']) {
  802. $sources[$i][$inprofile]['profilename'] = $profiles[$y]['Name'];
  803. $sources[$i][$inprofile]['profiletoken'] = $profiles[$y]['@attributes']['token'];
  804. if (isset($profiles[$y]['VideoEncoderConfiguration'])) {
  805. $sources[$i][$inprofile]['encoding'] = $profiles[$y]['VideoEncoderConfiguration']['Encoding'];
  806. $sources[$i][$inprofile]['width'] = $profiles[$y]['VideoEncoderConfiguration']['Resolution']['Width'];
  807. $sources[$i][$inprofile]['height'] = $profiles[$y]['VideoEncoderConfiguration']['Resolution']['Height'];
  808. $sources[$i][$inprofile]['fps'] = $profiles[$y]['VideoEncoderConfiguration']['RateControl']['FrameRateLimit'];
  809. $sources[$i][$inprofile]['bitrate'] = $profiles[$y]['VideoEncoderConfiguration']['RateControl']['BitrateLimit'];
  810. }
  811. if (isset($profiles[$y]['PTZConfiguration'])) {
  812. $sources[$i][$inprofile]['ptz']['name'] = $profiles[$y]['PTZConfiguration']['Name'];
  813. $sources[$i][$inprofile]['ptz']['nodetoken'] = $profiles[$y]['PTZConfiguration']['NodeToken'];
  814. }
  815. $inprofile++;
  816. }
  817. }
  818. }
  819. protected function _xml2array($response) {
  820. $sxe = new SimpleXMLElement($response);
  821. $dom_sxe = dom_import_simplexml($sxe);
  822. $dom = new DOMDocument('1.0');
  823. $dom_sxe = $dom->importNode($dom_sxe, true);
  824. $dom_sxe = $dom->appendChild($dom_sxe);
  825. $element = $dom->childNodes->item(0);
  826. foreach ($sxe->getDocNamespaces() as $name => $uri) {
  827. $element->removeAttributeNS($uri, $name);
  828. }
  829. $xmldata = $dom->saveXML();
  830. $xmldata = substr($xmldata, strpos($xmldata, "<Envelope>"));
  831. $xmldata = substr($xmldata, 0, strpos($xmldata, "</Envelope>") + strlen("</Envelope>"));
  832. @$xml = simplexml_load_string($xmldata);
  833. $data = json_decode(json_encode((array)$xml), 1);
  834. if ($data != array(0 => '')) { //shittiest workaround ever
  835. $data = array($xml->getName() => $data);
  836. } else {
  837. throw new Exception('FAILED');
  838. }
  839. return $data;
  840. }
  841. protected function _passwordDigest($username, $password, $timestamp = "default", $nonce = "default") {
  842. if ($timestamp == 'default') $timestamp = date('Y-m-d\TH:i:s.000\Z');
  843. if ($nonce == 'default') $nonce = mt_rand();
  844. $REQ = array();
  845. $passdigest = base64_encode(pack('H*', sha1(pack('H*', $nonce) . pack('a*', $timestamp) . pack('a*', $password))));
  846. //$passdigest=base64_encode(sha1($nonce.$timestamp.$password,true)); // alternative
  847. $REQ['USERNAME'] = $username;
  848. $REQ['PASSDIGEST'] = $passdigest;
  849. $REQ['NONCE'] = base64_encode(pack('H*', $nonce));
  850. //$REQ['NONCE']=base64_encode($nonce); // alternative
  851. $REQ['TIMESTAMP'] = $timestamp;
  852. return $REQ;
  853. }
  854. protected function _send_request($url, $post_string) {
  855. $soap_do = curl_init();
  856. curl_setopt($soap_do, CURLOPT_URL, $url);
  857. if ($this->proxyhost != '' && $this->proxyport != '') {
  858. curl_setopt($soap_do, CURLOPT_PROXY, $this->proxyhost);
  859. curl_setopt($soap_do, CURLOPT_PROXYPORT, $this->proxyport);
  860. if ($this->proxyusername != '' && $this->proxypassword != '')
  861. curl_setopt($soap_do, CURLOPT_PROXYUSERPWD, $this->proxyusername . ':' . $this->proxypassword);
  862. }
  863. curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);
  864. curl_setopt($soap_do, CURLOPT_TIMEOUT, 10);
  865. curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true);
  866. curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);
  867. curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);
  868. curl_setopt($soap_do, CURLOPT_POST, true);
  869. curl_setopt($soap_do, CURLOPT_POSTFIELDS, $post_string);
  870. curl_setopt($soap_do, CURLOPT_HTTPHEADER, array('Content-Type: text/xml; charset=utf-8', 'Content-Length: ' . strlen($post_string)));
  871. //curl_setopt($soap_do, CURLOPT_USERPWD, $user . ":" . $password); // HTTP authentication
  872. if (($result = curl_exec($soap_do)) === false) {
  873. $err = curl_error($soap_do);
  874. $this->lastresponse = array("Fault" => $err);
  875. } else {
  876. $this->lastresponse = $this->_xml2array($result);
  877. }
  878. return $this->lastresponse;
  879. }
  880. } // end class