/XMPPHP/BOSH.php

https://github.com/glex/xmpphp · PHP · 251 lines · 178 code · 25 blank · 48 comment · 28 complexity · 4c381ea932dea73afe7574c956c814f2 MD5 · raw file

  1. <?php
  2. /**
  3. * XMPPHP: The PHP XMPP Library
  4. * Copyright (C) 2008 Nathanael C. Fritz
  5. * This file is part of SleekXMPP.
  6. *
  7. * XMPPHP is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * XMPPHP is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with XMPPHP; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category xmpphp
  22. * @package XMPPHP
  23. * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
  24. * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
  25. * @author Michael Garvin <JID: gar@netflint.net>
  26. * @copyright 2008 Nathanael C. Fritz
  27. */
  28. /** XMPPHP_XMLStream */
  29. require_once dirname(__FILE__) . "/XMPP.php";
  30. /**
  31. * XMPPHP Main Class
  32. *
  33. * @category xmpphp
  34. * @package XMPPHP
  35. * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
  36. * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
  37. * @author Michael Garvin <JID: gar@netflint.net>
  38. * @copyright 2008 Nathanael C. Fritz
  39. * @version $Id$
  40. */
  41. class XMPPHP_BOSH extends XMPPHP_XMPP {
  42. protected $rid;
  43. protected $sid;
  44. protected $http_server;
  45. protected $http_buffer = Array();
  46. protected $session = false;
  47. protected $inactivity;
  48. public function connect($server=NULL, $wait='1', $session=false) {
  49. if (is_null( $server )) {
  50. //if we aren't given the server http url, try and guess it
  51. $port_string = ( $this->port && $this->port != 80 ) ? ":".$this->port : "";
  52. $this->http_server = "http://".$this->host."$port_string/http-bind/";
  53. } else {
  54. $this->http_server = $server;
  55. }
  56. $this->use_encryption = false;
  57. $this->session = $session;
  58. $this->rid = 3001;
  59. $this->sid = null;
  60. $this->inactivity=0;
  61. if($session)
  62. {
  63. $this->loadSession();
  64. }
  65. if(!$this->sid) {
  66. $body = $this->__buildBody();
  67. $body->addAttribute('hold','1');
  68. $body->addAttribute('to', $this->server);
  69. $body->addAttribute('route', "xmpp:{$this->host}:{$this->port}");
  70. $body->addAttribute('secure','true');
  71. $body->addAttribute('xmpp:version','1.0', 'urn:xmpp:xbosh');
  72. $body->addAttribute('wait', strval($wait));
  73. $body->addAttribute('ack','1');
  74. $body->addAttribute('xmlns:xmpp','urn:xmpp:xbosh');
  75. $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
  76. xml_parse($this->parser, $buff, false);
  77. $response = $this->__sendBody($body);
  78. $rxml = new SimpleXMLElement($response);
  79. $this->sid = $rxml['sid'];
  80. $this->inactivity = $rxml['inactivity'];
  81. } else {
  82. $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
  83. xml_parse($this->parser, $buff, false);
  84. }
  85. }
  86. public function __sendBody($body=null, $recv=true) {
  87. if(!$body) {
  88. $body = $this->__buildBody();
  89. }
  90. $ch = curl_init();
  91. curl_setopt($ch, CURLOPT_URL,$this->http_server);
  92. curl_setopt($ch, CURLOPT_HEADER, 0);
  93. curl_setopt($ch, CURLOPT_POST, 1);
  94. curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML());
  95. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  96. $header = array('Accept-Encoding: gzip, deflate','Content-Type: text/xml; charset=utf-8');
  97. curl_setopt($ch, CURLOPT_HTTPHEADER, $header );
  98. curl_setopt($ch, CURLOPT_VERBOSE, 0);
  99. $output = '';
  100. if($recv) {
  101. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  102. $output = curl_exec($ch);
  103. if(curl_getinfo($ch,CURLINFO_HTTP_CODE)!="200") throw new XMPPHP_Exception("Wrong response from server!");
  104. $this->http_buffer[] = $output;
  105. }
  106. curl_close($ch);
  107. return $output;
  108. }
  109. public function __buildBody($sub=null) {
  110. $xml = new SimpleXMLElement("<body xmlns='http://jabber.org/protocol/httpbind' xmlns:xmpp='urn:xmpp:xbosh' />");
  111. $xml->addAttribute('content', 'text/xml; charset=utf-8');
  112. $xml->addAttribute('rid', $this->rid);
  113. $this->rid += 1;
  114. if($this->sid) $xml->addAttribute('sid', $this->sid);
  115. #if($this->sid) $xml->addAttribute('xmlns', 'http://jabber.org/protocol/httpbind');
  116. $xml->addAttribute('xml:lang', 'en');
  117. if($sub !== NULL) { // ok, so simplexml is lame
  118. $p = dom_import_simplexml($xml);
  119. $c = dom_import_simplexml($sub);
  120. $cn = $p->ownerDocument->importNode($c, true);
  121. $p->appendChild($cn);
  122. $xml = simplexml_import_dom($p);
  123. }
  124. return $xml;
  125. }
  126. //null params are not used and just to statify Strict Function Declaration
  127. public function __process($null1=NULL,$null2=NULL) {
  128. if($this->http_buffer) {
  129. $this->__parseBuffer();
  130. } else {
  131. $this->__sendBody();
  132. $this->__parseBuffer();
  133. }
  134. $this->saveSession();
  135. return true;
  136. }
  137. public function __parseBuffer() {
  138. while ($this->http_buffer) {
  139. $idx = key($this->http_buffer);
  140. $buffer = $this->http_buffer[$idx];
  141. unset($this->http_buffer[$idx]);
  142. if($buffer) {
  143. $xml = new SimpleXMLElement($buffer);
  144. $children = $xml->xpath('child::node()');
  145. foreach ($children as $child) {
  146. $buff = $child->asXML();
  147. $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE);
  148. xml_parse($this->parser, $buff, false);
  149. }
  150. }
  151. }
  152. }
  153. //null params are not used and just to statify Strict Function Declaration
  154. public function send($msg,$null1=NULL) {
  155. $this->log->log("SEND: $msg", XMPPHP_Log::LEVEL_VERBOSE);
  156. $msg = new SimpleXMLElement($msg);
  157. #$msg->addAttribute('xmlns', 'jabber:client');
  158. $this->__sendBody($this->__buildBody($msg), true);
  159. #$this->__parseBuffer();
  160. }
  161. public function reset() {
  162. $this->xml_depth = 0;
  163. unset($this->xmlobj);
  164. $this->xmlobj = array();
  165. $this->setupParser();
  166. #$this->send($this->stream_start);
  167. $body = $this->__buildBody();
  168. $body->addAttribute('to', $this->host);
  169. $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh');
  170. $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
  171. $response = $this->__sendBody($body);
  172. $this->been_reset = true;
  173. xml_parse($this->parser, $buff, false);
  174. }
  175. public function loadSession() {
  176. if(session_id()==""){
  177. // session not started so use session_file
  178. $session_file = sys_get_temp_dir()."/".$this->user."_".$this->server."_session";
  179. // manage multiple accesses
  180. if(!file_exists($session_file)) file_put_contents($session_file,"");
  181. $session_file_fp = fopen($session_file,"r"); flock($session_file_fp,LOCK_EX);
  182. $session_serialized = file_get_contents($session_file, NULL, NULL, 6);
  183. $this->log->log("SESSION: reading $session_serialized from $session_file", XMPPHP_Log::LEVEL_VERBOSE);
  184. if($session_serialized!="")
  185. $_SESSION = unserialize($session_serialized);
  186. }
  187. if(isset($_SESSION['XMPPHP_BOSH_inactivity'])) $this->inactivity = $_SESSION['XMPPHP_BOSH_inactivity'];
  188. $this->lat = time() - (isset($_SESSION['XMPPHP_BOSH_lat'])? $_SESSION['XMPPHP_BOSH_lat'] : 0);
  189. if($this->lat<$this->inactivity){
  190. if(isset($_SESSION['XMPPHP_BOSH_RID'])) $this->rid = $_SESSION['XMPPHP_BOSH_RID'];
  191. if(isset($_SESSION['XMPPHP_BOSH_SID'])) $this->sid = $_SESSION['XMPPHP_BOSH_SID'];
  192. if(isset($_SESSION['XMPPHP_BOSH_authed'])) $this->authed = $_SESSION['XMPPHP_BOSH_authed'];
  193. if(isset($_SESSION['XMPPHP_BOSH_basejid'])) $this->basejid = $_SESSION['XMPPHP_BOSH_basejid'];
  194. if(isset($_SESSION['XMPPHP_BOSH_fulljid'])) $this->fulljid = $_SESSION['XMPPHP_BOSH_fulljid'];
  195. }
  196. }
  197. public function saveSession() {
  198. $_SESSION['XMPPHP_BOSH_RID'] = (string) $this->rid;
  199. $_SESSION['XMPPHP_BOSH_SID'] = (string) $this->sid;
  200. $_SESSION['XMPPHP_BOSH_authed'] = (boolean) $this->authed;
  201. $_SESSION['XMPPHP_BOSH_basejid'] = (string) $this->basejid;
  202. $_SESSION['XMPPHP_BOSH_fulljid'] = (string) $this->fulljid;
  203. $_SESSION['XMPPHP_BOSH_inactivity'] = (string) $this->inactivity;
  204. $_SESSION['XMPPHP_BOSH_lat'] = (string) time();
  205. if(session_id()==""){
  206. $session_file = sys_get_temp_dir()."/".$this->user."_".$this->server."_session";
  207. // <?php prefix used to mask the content of the session file
  208. $session_serialized = "<?php ".serialize($_SESSION);
  209. file_put_contents($session_file,$session_serialized);
  210. }
  211. }
  212. public function disconnect(){
  213. parent::disconnect();
  214. if(session_id()=="")
  215. unlink(sys_get_temp_dir()."/".$this->user."_".$this->server."_session");
  216. else{
  217. unset($_SESSION['XMPPHP_BOSH_RID']);
  218. unset($_SESSION['XMPPHP_BOSH_SID']);
  219. unset($_SESSION['XMPPHP_BOSH_authed']);
  220. unset($_SESSION['XMPPHP_BOSH_basejid']);
  221. unset($_SESSION['XMPPHP_BOSH_fulljid']);
  222. unset($_SESSION['XMPPHP_BOSH_inactivity']);
  223. unset($_SESSION['XMPPHP_BOSH_lat']);
  224. }
  225. }
  226. }