Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/piotr-cz/xmpp-prebind-php
Browse files Browse the repository at this point in the history
…into piotr-cz-master

Conflicts:
	lib/XmppPrebind.php
  • Loading branch information
mweibel committed Feb 19, 2015
2 parents 7ded9c0 + 305788e commit e7d4216
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 43 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,2 +1,3 @@
.DS_Store
.svn
.idea
20 changes: 20 additions & 0 deletions composer.json
@@ -0,0 +1,20 @@
{
"name": "piotr-cz/xmpp-prebind-php",
"description": "This class is for prebinding a XMPP Session with PHP.",
"authors": [
{
"name": "Michael Weibel"
},
{
"name": "piotr",
"email": "hello@piotr.cz"
}
],
"autoload": {
"classmap": ["lib/"]
},
"require": {
"php": ">=5.3",
"lib-libxml": "*"
}
}
158 changes: 115 additions & 43 deletions lib/XmppPrebind.php
Expand Up @@ -38,33 +38,51 @@ class XmppPrebind {

const SERVICE_NAME = 'xmpp';

private $jabberHost = '';
private $boshUri = '';
private $resource = '';
protected $jabberHost = '';
protected $boshUri = '';
protected $resource = '';

private $debug = false;
protected $debug = false;
/**
* FirePHP Instance
*
* @var FirePHP
*/
private $firePhp = null;
protected $firePhp = null;

private $useGzip = false;
private $useSsl = false;
private $encryption = self::ENCRYPTION_PLAIN;
protected $useGzip = false;
protected $useSsl = false;
protected $encryption = self::ENCRYPTION_PLAIN;

private $jid = '';
private $password = '';
protected $jid = '';
protected $password = '';

private $rid = '';
private $sid = '';
protected $rid = '';
protected $sid = '';

private $doSession = false;
private $doBind = false;
protected $doSession = false;
protected $doBind = false;

private $mechanisms = array();
protected $mechanisms = array();

// the Bosh attributes for use in a client using this prebound session
protected $wait;
protected $requests;
protected $ver;
protected $polling;
protected $inactivity;
protected $hold;
protected $to;
protected $ack;
protected $accept;
protected $maxpause;

/**
* Session creation response
*
* @var DOMDocument
*/
public $response;

/**
* Create a new XmppPrebind Object with the required params
Expand Down Expand Up @@ -114,24 +132,44 @@ public function __construct($jabberHost, $boshUri, $resource, $useSsl = false, $
*
* @param string $username Username without jabber host
* @param string $password Password
* @param string $route Route
*/
public function connect($username, $password) {
$this->jid = $username . '@' . $this->jabberHost . '/' . $this->resource;
public function connect($username, $password, $route = false) {
$this->jid = $username . '@' . $this->jabberHost;

if($this->resource) {
$this->jid .= '/' . $this->resource;
}

$this->password = $password;

$response = $this->sendInitialConnection();
if ( empty( $response ) )
$response = $this->sendInitialConnection($route);
if(empty($response)) {
throw new XmppPrebindConnectionException("No response from server.");
}

$body = self::getBodyFromXml($response);
if ( empty( $body ) )
throw new XmppPrebindConnectionException("No body could be found in response from server.");
$this->sid = $body->getAttribute('sid');

// set the Bosh Attributes
$this->wait = $body->getAttribute('wait');
$this->requests = $body->getAttribute('requests');
$this->ver = $body->getAttribute('ver');
$this->polling = $body->getAttribute('polling');
$this->inactivity = $body->getAttribute('inactivity');
$this->hold = $body->getAttribute('hold');
$this->to = $body->getAttribute('to');
$this->accept = $body->getAttribute('accept');
$this->maxpause = $body->getAttribute('maxpause');

$this->debug($this->sid, 'sid');

if ( empty( $body->firstChild ) || empty( $body->firstChild->firstChild ) )
if(empty($body->firstChild) || empty($body->firstChild->firstChild)) {
throw new XmppPrebindConnectionException("Child not found in response from server.");
$mechanisms = $body->firstChild->firstChild->getElementsByTagName('mechanism');
}
$mechanisms = $body->getElementsByTagName('mechanism');

foreach ($mechanisms as $value) {
$this->mechanisms[] = $value->nodeValue;
Expand All @@ -148,6 +186,9 @@ public function connect($username, $password) {
}

$this->debug($this->encryption, 'encryption used');

// Assign session creation response
$this->response = $body;
}

/**
Expand Down Expand Up @@ -185,6 +226,27 @@ public function auth() {
return true;
}

/**
* Get BOSH parameters to properly setup the BOSH client
*
* @return array
*/
public function getBoshInfo()
{
return array(
'wait' => $this->wait,
'requests' => $this->requests,
'ver' => $this->ver,
'polling' => $this->polling,
'inactivity' => $this->inactivity,
'hold' => $this->hold,
'to' => $this->to,
'ack' => $this->ack,
'accept' => $this->accept,
'maxpause' => $this->maxpause,
);
}

/**
* Get jid, sid and rid for attaching
*
Expand All @@ -200,7 +262,7 @@ public function getSessionInfo() {
* @param string $msg
* @param string $label
*/
private function debug($msg, $label = null) {
protected function debug($msg, $label = null) {
if ($this->firePhp) {
$this->firePhp->log($msg, $label);
}
Expand All @@ -211,7 +273,7 @@ private function debug($msg, $label = null) {
*
* @return string Response
*/
private function sendRestart() {
protected function sendRestart() {
$domDocument = $this->buildBody();
$body = self::getBodyFromDomDocument($domDocument);
$body->appendChild(self::getNewTextAttribute($domDocument, 'to', $this->jabberHost));
Expand Down Expand Up @@ -241,7 +303,7 @@ private function sendRestart() {
*
* @return string Response
*/
private function sendBindIfRequired() {
protected function sendBindIfRequired() {
if ($this->doBind) {
$domDocument = $this->buildBody();
$body = self::getBodyFromDomDocument($domDocument);
Expand Down Expand Up @@ -269,7 +331,7 @@ private function sendBindIfRequired() {
/**
* Send session if there's a session node in the restart response (within stream:features)
*/
private function sendSessionIfRequired() {
protected function sendSessionIfRequired() {
if ($this->doSession) {
$domDocument = $this->buildBody();
$body = self::getBodyFromDomDocument($domDocument);
Expand All @@ -293,9 +355,10 @@ private function sendSessionIfRequired() {
/**
* Send initial connection string
*
* @param string $route
* @return string Response
*/
private function sendInitialConnection() {
protected function sendInitialConnection($route = false) {
$domDocument = $this->buildBody();
$body = self::getBodyFromDomDocument($domDocument);

Expand All @@ -307,6 +370,11 @@ private function sendInitialConnection() {
$body->appendChild(self::getNewTextAttribute($domDocument, 'xmpp:version', '1.0'));
$body->appendChild(self::getNewTextAttribute($domDocument, 'wait', $waitTime));

if ($route)
{
$body->appendChild(self::getNewTextAttribute($domDocument, 'route', $route));
}

return $this->send($domDocument->saveXML());
}

Expand All @@ -315,7 +383,7 @@ private function sendInitialConnection() {
*
* @return string Challenge
*/
private function sendChallenge() {
protected function sendChallenge() {
$domDocument = $this->buildBody();
$body = self::getBodyFromDomDocument($domDocument);

Expand All @@ -338,7 +406,7 @@ private function sendChallenge() {
* @param Auth_SASL_Common $auth
* @return string Auth XML to send
*/
private function buildPlainAuth(Auth_SASL_Common $auth) {
protected function buildPlainAuth(Auth_SASL_Common $auth) {
$authString = $auth->getResponse(self::getNodeFromJid($this->jid), $this->password, self::getBareJidFromJid($this->jid));
$authString = base64_encode($authString);
$this->debug($authString, 'PLAIN Auth String');
Expand All @@ -361,10 +429,10 @@ private function buildPlainAuth(Auth_SASL_Common $auth) {
* @param Auth_SASL_Common $auth
* @return string Auth XML to send
*/
private function sendChallengeAndBuildDigestMd5Auth(Auth_SASL_Common $auth) {
protected function sendChallengeAndBuildDigestMd5Auth(Auth_SASL_Common $auth) {
$challenge = $this->sendChallenge();

$authString = $auth->getResponse(self::getNodeFromJid($this->jid), $this->password, $challenge, $this->jabberHost, self::SERVICE_NAME, $this->jid);
$authString = $auth->getResponse(self::getNodeFromJid($this->jid), $this->password, $challenge, $this->jabberHost, self::SERVICE_NAME);
$this->debug($authString, 'DIGEST-MD5 Auth String');

$authString = base64_encode($authString);
Expand All @@ -390,7 +458,7 @@ private function sendChallengeAndBuildDigestMd5Auth(Auth_SASL_Common $auth) {
* @param Auth_SASL_Common $auth
* @return string Auth XML to send
*/
private function sendChallengeAndBuildCramMd5Auth(Auth_SASL_Common $auth) {
protected function sendChallengeAndBuildCramMd5Auth(Auth_SASL_Common $auth) {
$challenge = $this->sendChallenge();

$authString = $auth->getResponse(self::getNodeFromJid($this->jid), $this->password, $challenge);
Expand All @@ -416,7 +484,7 @@ private function sendChallengeAndBuildCramMd5Auth(Auth_SASL_Common $auth) {
* CRAM-MD5 and DIGEST-MD5 reply with an additional challenge response which must be replied to.
* After this additional reply, the server should reply with "success".
*/
private function replyToChallengeResponse($challengeResponse) {
protected function replyToChallengeResponse($challengeResponse) {
$body = self::getBodyFromXml($challengeResponse);
$challenge = base64_decode((string)$body->firstChild->nodeValue);
if (strpos($challenge, 'rspauth') === false) {
Expand All @@ -439,7 +507,7 @@ private function replyToChallengeResponse($challengeResponse) {
* @param string $xml
* @return string Response
*/
private function send($xml) {
protected function send($xml) {
$ch = curl_init($this->boshUri);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
Expand All @@ -457,6 +525,11 @@ private function send($xml) {

$response = curl_exec($ch);

// Check if curl failed to get response
if ($response === false) {
throw new XmppPrebindConnectionException("Cannot connect to service");
}

curl_close($ch);

if ($this->useGzip) {
Expand Down Expand Up @@ -487,11 +560,11 @@ public static function compatibleGzInflate($gzData) {
$i = $i + 2 + $xlen;
}
if ( $flg & 8 )
$i = strpos($gzData, "\0", $i) + 1;
$i = strpos($gzData, "\0", $i) + 1;
if ( $flg & 16 )
$i = strpos($gzData, "\0", $i) + 1;
$i = strpos($gzData, "\0", $i) + 1;
if ( $flg & 2 )
$i = $i + 2;
$i = $i + 2;
}
return gzinflate( substr($gzData, $i, -8) );
} else {
Expand All @@ -504,7 +577,7 @@ public static function compatibleGzInflate($gzData) {
*
* @return DOMDocument
*/
private function buildBody() {
protected function buildBody() {
$xml = new DOMDocument('1.0', 'UTF-8');

$body = $xml->createElement('body');
Expand Down Expand Up @@ -558,7 +631,7 @@ public static function getNodeFromJid($jid) {
* @param string $value
* @return DOMNode
*/
private static function getNewTextAttribute($domDocument, $attributeName, $value) {
protected static function getNewTextAttribute($domDocument, $attributeName, $value) {
$attribute = $domDocument->createAttribute($attributeName);
$attribute->appendChild($domDocument->createTextNode($value));

Expand All @@ -571,7 +644,7 @@ private static function getNewTextAttribute($domDocument, $attributeName, $value
* @param DOMDocument $domDocument
* @return DOMNode
*/
private static function getBodyFromDomDocument($domDocument) {
protected static function getBodyFromDomDocument($domDocument) {
$body = $domDocument->getElementsByTagName('body');
return $body->item(0);
}
Expand All @@ -583,7 +656,7 @@ private static function getBodyFromDomDocument($domDocument) {
* @param string $xml
* @return DOMNode
*/
private static function getBodyFromXml($xml) {
protected static function getBodyFromXml($xml) {
$domDocument = new DOMDocument();
$domDocument->loadXml($xml);

Expand All @@ -596,15 +669,14 @@ private static function getBodyFromXml($xml) {
*
* @return int
*/
private function getAndIncrementRid() {
protected function getAndIncrementRid() {
return $this->rid++;
}

}

/**
* Standard XmppPrebind Exception
*/
class XmppPrebindException extends Exception{}

class XmppPrebindConnectionException extends XmppPrebindException {}
class XmppPrebindConnectionException extends XmppPrebindException{}

0 comments on commit e7d4216

Please sign in to comment.