PageRenderTime 208ms CodeModel.GetById 31ms RepoModel.GetById 4ms app.codeStats 0ms

/tests/jabber/xmpphp/xmlstream.php

https://github.com/ntulip/twitterpg
PHP | 341 lines | 295 code | 22 blank | 24 comment | 56 complexity | b26cdcab802a76fff90dcc453bfa6816 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /*
  3. XMPPHP: The PHP XMPP Library
  4. Copyright (C) 2008 Nathanael C. Fritz
  5. This file is part of SleekXMPP.
  6. XMPPHP is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. XMPPHP is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with XMPPHP; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. require_once("xmlobj.php");
  19. require_once("logging.php");
  20. class XMLStream {
  21. var $socket;
  22. var $parser;
  23. var $buffer;
  24. var $xml_depth = 0;
  25. var $host;
  26. var $port;
  27. var $stream_start = '<stream>';
  28. var $stream_end = '</stream';
  29. var $disconnected = false;
  30. var $sent_disconnect = False;
  31. var $ns_map = array();
  32. var $current_ns = array();
  33. var $xmlobj = Null;
  34. var $nshandlers = array();
  35. var $idhandlers = array();
  36. var $eventhandlers = array();
  37. var $lastid = 0;
  38. var $default_ns;
  39. var $until = '';
  40. var $until_happened = False;
  41. var $until_payload = array();
  42. var $log;
  43. var $reconnect = True;
  44. var $been_reset = False;
  45. var $is_server;
  46. function XMLStream($host=Null, $port=Null, $log=False, $loglevel=Null, $is_server=False) {
  47. $this->reconnect = !$is_server;
  48. $this->is_server = $is_server;
  49. $this->host = $host;
  50. $this->port = $port;
  51. $this->setupParser();
  52. $this->log = new Logging($log, $loglevel);
  53. }
  54. function getId() {
  55. $this->lastid++;
  56. return $this->lastid;
  57. }
  58. function addIdHandler($id, $pointer, $obj=Null) {
  59. $this->idhandlers[$id] = array($pointer, $obj);
  60. }
  61. function addHandler($name, $ns, $pointer, $obj=Null, $depth=1) {
  62. $this->nshandlers[] = array($name,$ns,$pointer,$obj, $depth);
  63. }
  64. function addEventHandler($name, $pointer, $obj) {
  65. $this->eventhanders[] = array($name, $pointer, $obj);
  66. }
  67. function connect($persistent=False, $sendinit=True) {
  68. $this->disconnected = False;
  69. $this->sent_disconnect = False;
  70. if($persistent) {
  71. $conflag = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
  72. } else {
  73. $conflag = STREAM_CLIENT_CONNECT;
  74. }
  75. $this->log->log("Connecting to tcp://{$this->host}:{$this->port}");
  76. $this->socket = stream_socket_client("tcp://{$this->host}:{$this->port}", $flags=$conflag);
  77. if(!$this->socket) {
  78. $this->log->log("Could not connect.", LOGGING_ERROR);
  79. $this->disconnected = True;
  80. }
  81. stream_set_blocking($this->socket, 1);
  82. if($sendinit) $this->send($this->stream_start);
  83. }
  84. function apply_socket($socket) {
  85. $this->socket = $socket;
  86. }
  87. function process() {
  88. $updated = '';
  89. while(!$this->disconnect) {
  90. $read = array($this->socket);
  91. $write = NULL;
  92. $except = NULL;
  93. $updated = stream_select($read, $write, $except, 1);
  94. if ($updated > 0) {
  95. $buff = @fread($this->socket, 1024);
  96. if(!$buff) {
  97. if($this->reconnect) {
  98. $this->doReconnect();
  99. } else {
  100. fclose($this->socket);
  101. return False;
  102. }
  103. }
  104. $this->log->log("RECV: $buff", LOGGING_VERBOSE);
  105. xml_parse($this->parser, $buff, False);
  106. }
  107. }
  108. }
  109. function read() {
  110. $buff = @fread($this->socket, 1024);
  111. if(!$buff) {
  112. if($this->reconnect) {
  113. $this->doReconnect();
  114. } else {
  115. fclose($this->socket);
  116. return False;
  117. }
  118. }
  119. $this->log->log("RECV: $buff", LOGGING_VERBOSE);
  120. xml_parse($this->parser, $buff, False);
  121. }
  122. function processTime($timeout=-1) {
  123. $start = time();
  124. $updated = '';
  125. while(!$this->disconnected and ($timeout == -1 or time() - $start < $timeout)) {
  126. $read = array($this->socket);
  127. $write = NULL;
  128. $except = NULL;
  129. $updated = stream_select($read, $write, $except, 1);
  130. if ($updated > 0) {
  131. $buff = @fread($this->socket, 1024);
  132. if(!$buff) {
  133. if($this->reconnect) {
  134. $this->doReconnect();
  135. } else {
  136. fclose($this->socket);
  137. return False;
  138. }
  139. }
  140. $this->log->log("RECV: $buff", LOGGING_VERBOSE);
  141. xml_parse($this->parser, $buff, False);
  142. }
  143. }
  144. }
  145. function processUntil($event, $timeout=-1) {
  146. $start = time();
  147. if(!is_array($event)) $event = array($event);
  148. $this->until[] = $event;
  149. end($this->until);
  150. $event_key = key($this->until);
  151. reset($this->until);
  152. $updated = '';
  153. while(!$this->disconnected and $this->until[$event_key] and (time() - $start < $timeout or $timeout == -1)) {
  154. $read = array($this->socket);
  155. $write = NULL;
  156. $except = NULL;
  157. $updated = stream_select($read, $write, $except, 1);
  158. if ($updated > 0) {
  159. $buff = @fread($this->socket, 1024);
  160. if(!$buff) {
  161. if($this->reconnect) {
  162. $this->doReconnect();
  163. } else {
  164. fclose($this->socket);
  165. return False;
  166. }
  167. }
  168. $this->log->log("RECV: $buff", LOGGING_VERBOSE);
  169. xml_parse($this->parser, $buff, False);
  170. }
  171. }
  172. $payload = $this->until_payload[$event_key];
  173. unset($this->until_payload[$event_key]);
  174. return $payload;
  175. }
  176. function startXML($parser, $name, $attr) {
  177. if($this->been_reset) {
  178. $this->been_reset = False;
  179. $this->xml_depth = 0;
  180. }
  181. $this->xml_depth++;
  182. if(array_key_exists('XMLNS', $attr)) {
  183. $this->current_ns[$this->xml_depth] = $attr['XMLNS'];
  184. } else {
  185. $this->current_ns[$this->xml_depth] = $this->current_ns[$this->xml_depth - 1];
  186. if(!$this->current_ns[$this->xml_depth]) $this->current_ns[$this->xml_depth] = $this->default_ns;
  187. }
  188. $ns = $this->current_ns[$this->xml_depth];
  189. foreach($attr as $key => $value) {
  190. if(strstr($key, ":")) {
  191. $key = explode(':', $key);
  192. $key = $key[1];
  193. $this->ns_map[$key] = $value;
  194. }
  195. }
  196. if(!strstr($name, ":") === False)
  197. {
  198. $name = explode(':', $name);
  199. $ns = $this->ns_map[$name[0]];
  200. $name = $name[1];
  201. }
  202. $obj = new XMLObj($name, $ns, $attr);
  203. if($this->xml_depth > 1)
  204. $this->xmlobj[$this->xml_depth - 1]->subs[] = $obj;
  205. $this->xmlobj[$this->xml_depth] = $obj;
  206. }
  207. function endXML($parser, $name) {
  208. #$this->log->log("Ending $name", LOGGING_DEBUG);
  209. #print "$name\n";
  210. if($this->been_reset) {
  211. $this->been_reset = False;
  212. $this->xml_depth = 0;
  213. }
  214. $this->xml_depth--;
  215. if($this->xml_depth == 1) {
  216. #clean-up old objects
  217. $found = False;
  218. foreach($this->nshandlers as $handler) {
  219. if($handler[4] != 1 and $this->xmlobj[2]->hassub($handler[0])) {
  220. $searchxml = $this->xmlobj[2]->sub($handler[0]);
  221. } else {
  222. $searchxml = $this->xmlobj[2];
  223. }
  224. if($searchxml->name == $handler[0] and ($searchxml->ns == $handler[1] or (!$handler[1] and $searchxml->ns == $this->default_ns))) {
  225. if($handler[3] === Null) $handler[3] = $this;
  226. $this->log->log("Calling {$handler[2]}", LOGGING_DEBUG);
  227. call_user_method($handler[2], $handler[3], $this->xmlobj[2]);
  228. }
  229. }
  230. foreach($this->idhandlers as $id => $handler) {
  231. if($this->xmlobj[2]->attrs['id'] == $id) {
  232. if($handler[1] === Null) $handler[1] = $this;
  233. call_user_method($handler[0], $handler[1], $this->xmlobj[2]);
  234. #id handlers are only used once
  235. unset($this->idhandlers[$id]);
  236. break;
  237. }
  238. }
  239. if(is_array($this->xmlobj)) {
  240. $this->xmlobj = array_slice($this->xmlobj, 0, 1);
  241. $this->xmlobj[0]->subs = Null;
  242. }
  243. unset($this->xmlobj[2]);
  244. }
  245. if($this->xml_depth == 0 and !$this->been_reset) {
  246. if(!$this->disconnected) {
  247. if(!$this->sent_disconnect) {
  248. $this->send($this->stream_end);
  249. }
  250. $this->disconnected = True;
  251. $this->sent_disconnect = True;
  252. fclose($this->socket);
  253. if($this->reconnect) {
  254. $this->doReconnect();
  255. }
  256. }
  257. $this->event('end_stream');
  258. }
  259. }
  260. function doReconnect() {
  261. if(!$this->is_server) {
  262. $this->log->log("Reconnecting...", LOGGING_WARNING);
  263. $this->connect(False, False);
  264. $this->reset();
  265. }
  266. }
  267. function disconnect() {
  268. $this->reconnect = False;
  269. $this->send($this->stream_end);
  270. $this->sent_disconnect = True;
  271. $this->processUntil('end_stream', 5);
  272. $this->disconnected = True;
  273. }
  274. function event($name, $payload=Null) {
  275. $this->log->log("EVENT: $name", LOGGING_DEBUG);
  276. foreach($this->eventhandlers as $handler) {
  277. if($name == $handler[0]) {
  278. if($handler[2] === Null) $handler[2] = $this;
  279. call_user_method($handler[1], $handler[2], $payload);
  280. }
  281. }
  282. foreach($this->until as $key => $until) {
  283. if(is_array($until)) {
  284. if(in_array($name, $until)) {
  285. $this->until_payload[$key][] = array($name, $payload);
  286. $this->until[$key] = False;
  287. }
  288. }
  289. }
  290. }
  291. function charXML($parser, $data) {
  292. $this->xmlobj[$this->xml_depth]->data .= $data;
  293. }
  294. function send($msg) {
  295. #socket_write($this->socket, $msg);
  296. $this->log->log("SENT: $msg", LOGGING_VERBOSE);
  297. fwrite($this->socket, $msg);
  298. }
  299. function reset() {
  300. $this->xml_depth = 0;
  301. unset($this->xmlobj);
  302. $this->setupParser();
  303. if(!$this->is_server) {
  304. $this->send($this->stream_start);
  305. }
  306. $this->been_reset = True;
  307. }
  308. function setupParser() {
  309. $this->parser = xml_parser_create('UTF-8');
  310. xml_parser_set_option($this->parser,XML_OPTION_SKIP_WHITE,1);
  311. xml_parser_set_option($this->parser,XML_OPTION_TARGET_ENCODING, "UTF-8");
  312. xml_set_object($this->parser, $this);
  313. xml_set_element_handler($this->parser, 'startXML', 'endXML');
  314. xml_set_character_data_handler($this->parser, 'charXML');
  315. }
  316. }