Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "ably/ably-php",
"description": "Ably REST client library for PHP.",
"keywords": ["messaging", "messages", "ably"],
"version": "1.0.1",
"homepage": "https://www.ably.io/",
"require": {
"php": ">=5.4",
Expand Down
18 changes: 13 additions & 5 deletions src/AblyRest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
use Ably\Exceptions\AblyException;
use Ably\Exceptions\AblyRequestException;

/**
* Ably REST client
*/
class AblyRest {

private $options;
Expand All @@ -25,7 +28,7 @@ class AblyRest {

/**
* Constructor
* @param \Ably\Models\ClientOptions|string options or a string with app key or token
* @param \Ably\Models\ClientOptions|string array with options or a string with app key or token
*/
public function __construct( $options = array() ) {

Expand All @@ -43,6 +46,8 @@ public function __construct( $options = array() ) {
Log::setLogLevel( $this->options->logLevel );
if ( !empty( $this->options->logHandler ) ) {
Log::setLogCallback( $this->options->logHandler );
} else {
Log::setLogCallback( null );
}

$httpClass = $this->options->httpClass;
Expand All @@ -54,6 +59,7 @@ public function __construct( $options = array() ) {
}

/**
* Shorthand to $this->channels->get()
* @return \Ably\Channel Channel
*/
public function channel( $name, $options = array() ) {
Expand All @@ -70,15 +76,17 @@ public function stats( $params = array() ) {
}

/**
* @return integer server's time
* Retrieves server time
* @return integer server time in milliseconds
*/
public function time() {
$res = $this->get( '/time', $params = array(), $headers = array(), $returnHeaders = false, $authHeaders = false );
return $res[0];
}

/**
* @return integer system time
* Returns local time
* @return integer system time in milliseconds
*/
public function systemTime() {
return round( microtime(true) * 1000 );
Expand Down Expand Up @@ -131,7 +139,7 @@ public function request( $method, $path, $headers = array(), $params = array(),

$causedByExpiredToken = $auth
&& !$this->auth->isUsingBasicAuth()
&& $e->getAblyCode() == 40140;
&& $e->getCode() == 40140;

if ( $causedByExpiredToken ) { // renew the token
$this->auth->authorise( array(), array(), $force = true );
Expand Down Expand Up @@ -167,7 +175,7 @@ protected function requestWithFallback( $method, $path, $headers = array(), $par
return $this->http->request( $method, $server . $path, $headers, $params );
}
catch (AblyRequestException $e) {
if ( $e->getAblyCode() >= 50000 ) {
if ( $e->getCode() >= 50000 ) {
if ( $attempt < count( $this->options->fallbackHosts ) ) {
return $this->requestWithFallback( $method, $path, $headers, $params, $attempt + 1);
} else {
Expand Down
14 changes: 7 additions & 7 deletions src/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function __construct( AblyRest $ably, ClientOptions $options ) {

if ( !$options->tls ) {
log::e( 'Auth: trying to use basic key auth over insecure connection' );
throw new AblyException ( 'Trying to use basic key auth over insecure connection', 401, 40103 );
throw new AblyException ( 'Trying to use basic key auth over insecure connection', 40103, 401 );
}
return;
}
Expand All @@ -46,7 +46,7 @@ public function __construct( AblyRest $ably, ClientOptions $options ) {
Log::d( 'Auth: using token auth with supplied token only' );
} else {
Log::e( 'Auth: no authentication parameters supplied' );
throw new AblyException ( 'No authentication parameters supplied', 401, 40103 );
throw new AblyException ( 'No authentication parameters supplied', 40103, 401 );
}

$this->tokenDetails = $this->authOptions->tokenDetails;
Expand Down Expand Up @@ -93,7 +93,7 @@ public function getAuthHeaders() {
$this->authorise();
$header = array( 'authorization: Bearer '. base64_encode( $this->tokenDetails->token ) );
} else {
throw new AblyException( 'Unable to provide auth headers. No auth parameters defined.', 401, 40101 );
throw new AblyException( 'Unable to provide auth headers. No auth parameters defined.', 40101, 401 );
}
return $header;
}
Expand Down Expand Up @@ -173,7 +173,7 @@ public function requestToken( $authOptions = array(), $tokenParams = array() ) {
$signedTokenRequest = $this->createTokenRequest( $authOptions->toArray(), $tokenParams->toArray() );
} else {
Log::e( 'Auth::requestToken:', 'Unable to request a Token, auth options don\'t provide means to do so' );
throw new AblyException( 'Unable to request a Token, auth options don\'t provide means to do so', 401, 40101 );
throw new AblyException( 'Unable to request a Token, auth options don\'t provide means to do so', 40101, 401 );
}

// do the request
Expand All @@ -193,7 +193,7 @@ public function requestToken( $authOptions = array(), $tokenParams = array() ) {
);

if ( empty( $res->token ) ) { // just in case.. an AblyRequestException should be thrown on the previous step with a 4XX error code on failure
throw new AblyException( 'Failed to get a token', 401, 40100 );
throw new AblyException( 'Failed to get a token', 40100, 401 );
}

return new TokenDetails( $res );
Expand All @@ -213,7 +213,7 @@ public function createTokenRequest( $authOptions = array(), $tokenParams = array

if ( count( $keyParts ) != 2 ) {
Log::e( 'Auth::createTokenRequest', "Can't create signed token request, invalid key specified" );
throw new AblyException( 'Invalid key specified', 401, 40101 );
throw new AblyException( 'Invalid key specified', 40101, 401 );
}

$keyName = $keyParts[0];
Expand All @@ -222,7 +222,7 @@ public function createTokenRequest( $authOptions = array(), $tokenParams = array
$tokenRequest = new TokenRequest( $tokenParams );

if ( !empty( $tokenRequest->keyName ) && $tokenRequest->keyName != $keyName ) {
throw new AblyException( 'Incompatible keys specified', 401, 40102 );
throw new AblyException( 'Incompatible keys specified', 40102, 401 );
} else {
$tokenRequest->keyName = $keyName;
}
Expand Down
8 changes: 0 additions & 8 deletions src/Exceptions/AblyEncryptionException.php

This file was deleted.

34 changes: 25 additions & 9 deletions src/Exceptions/AblyException.php
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
<?php
namespace Ably\Exceptions;

use Exception;
use Ably\Models\ErrorInfo;
use \Exception;

/**
* Generic exception for Ably classes
* Generic Ably exception
*/
class AblyException extends Exception {

protected $ablyCode;

public function __construct($message, $code = 400, $ablyCode = 40000) {
parent::__construct($message, $code);
/**
* @var ErrorInfo
*/
public $errorInfo;

$this->ablyCode = $ablyCode;
public function __construct( $message, $code = null, $statusCode = null ) {
parent::__construct( $message, $code );
$this->errorInfo = new ErrorInfo();
$this->errorInfo->message = $message;
$this->errorInfo->code = $code;
$this->errorInfo->statusCode = $statusCode;
}

public function getAblyCode() {
return $this->ablyCode;
public function getStatusCode() {
return $this->errorInfo->statusCode;
}

// PHP doesn't allow overriding these methods

// public function getCode() {
// return $this->errorInfo->code;
// }

// public function getMessage() {
// return $this->errorInfo->message;
// }
}
4 changes: 2 additions & 2 deletions src/Exceptions/AblyRequestException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class AblyRequestException extends AblyException {

protected $response;

public function __construct( $message, $code, $ablyCode, $response = null ) {
parent::__construct( $message, $code, $ablyCode );
public function __construct( $message, $code, $statusCode, $response = null ) {
parent::__construct( $message, $code, $statusCode );

$this->response = $response ? : array( 'headers' => '', 'body' => '' );
}
Expand Down
6 changes: 3 additions & 3 deletions src/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public function request( $method, $url, $headers = array(), $params = array() )

if ($err) { // a connection error has occured (no data received)
Log::e('cURL error:', $err, $errmsg);
throw new AblyRequestException( 'cURL error: ' . $errmsg, 500, 50003 );
throw new AblyRequestException( 'cURL error: ' . $errmsg, 50003, 500 );
}

$response = null;
Expand All @@ -160,10 +160,10 @@ public function request( $method, $url, $headers = array(), $params = array() )
Log::v( 'cURL request response:', $info['http_code'], $response );

if ( !in_array( $info['http_code'], array(200,201) ) ) {
$ablyCode = empty( $decodedBody->error->code ) ? null : $decodedBody->error->code;
$ablyCode = empty( $decodedBody->error->code ) ? $info['http_code'] * 100 : $decodedBody->error->code * 1;
$errorMessage = empty( $decodedBody->error->message ) ? 'cURL request failed' : $decodedBody->error->message;

throw new AblyRequestException( $errorMessage, $info['http_code'], $ablyCode, $response );
throw new AblyRequestException( $errorMessage, $ablyCode, $info['http_code'], $response );
}

return $response;
Expand Down
5 changes: 0 additions & 5 deletions src/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ public static function setLogLevel( $logLevel ) {
*/
public static function setLogCallback( $function = null ) {
self::$logCallback = $function;
if ( $function ) {
self::v( 'Set custom logging callback function' );
} else {
self::v( 'Restored default logging function' );
}
}

/**
Expand Down
57 changes: 32 additions & 25 deletions src/Models/BaseMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
namespace Ably\Models;

use Ably\Exceptions\AblyException;
use Ably\Exceptions\AblyEncryptionException;
use Ably\Utils\Crypto;
use Ably\Log;

/**
* Base class for messages sent over channels.
Expand Down Expand Up @@ -75,7 +75,7 @@ public function fromJSON( $json, $keepOriginal = false ) {
} else {
$obj = @json_decode($json);
if (!$obj) {
throw new AblyException( 'Invalid object or JSON encoded object', 400, 40000 );
throw new AblyException( 'Invalid object or JSON encoded object' );
}
}

Expand Down Expand Up @@ -104,30 +104,29 @@ protected function encode() {
return $msg;
}

if (is_array( $this->data ) || is_object( $this->data )) {

if ( is_array( $this->data ) || $this->data instanceof \stdClass ) {
$type = 'json/utf-8';
$msg->data = json_encode($this->data);
} else if (!mb_check_encoding( $this->data, 'UTF-8' )) { // non-UTF-8, most likely a binary string

if (!$this->cipherParams) {
$type = 'base64';
$msg->data = base64_encode( $this->data );
} else {
$type = '';
} else if ( is_string( $this->data ) ){
if ( mb_check_encoding( $this->data, 'UTF-8' ) ) { // it's a UTF-8 string
$type = 'utf-8';
$msg->data = $this->data;
} else { // not UTF-8, assuming it's a binary string
if ($this->cipherParams) { // encryption will automatically base64 encode the data
$type = '';
$msg->data = $this->data;
} else {
$type = 'base64';
$msg->data = base64_encode( $this->data );
}
}
} else if ( is_string( $this->data ) ){ // it's a UTF-8 string

$type = 'utf-8';
$msg->data = $this->data;
} else {
throw new AblyException( 'Message data must be either, string, string with binary data, or JSON-encodable array or object.' );
throw new AblyException( 'Message data must be either, string, string with binary data, or JSON-encodable array or object.', 40003, 400 );
}

if ($this->cipherParams) {
$msg->data = base64_encode( Crypto::encrypt( $msg->data, $this->cipherParams ) );
$msg->encoding = $type . '/cipher+' . $this->cipherParams->algorithm . '/base64';
$msg->encoding = ( $type ? $type . '/' : '' ) . 'cipher+' . $this->cipherParams->algorithm . '/base64';
} else {
$msg->encoding = $type;
}
Expand All @@ -138,7 +137,6 @@ protected function encode() {
/**
* Decodes message's data field according to encoding
* @throws AblyException
* @throws AblyEncryptionException
*/
protected function decode() {
$this->originalData = $this->data;
Expand All @@ -152,28 +150,37 @@ protected function decode() {
$this->data = base64_decode( $this->data );

if ($this->data === false) {
throw new AblyException( 'Could not base64-decode message data', 400, 40000 );
throw new AblyException( 'Could not base64-decode message data' );
}

array_pop( $encodings );
} else if ($encoding == 'json') {
$this->data = json_decode( $this->data );

if ($this->data === null) {
throw new AblyException( 'Could not JSON-decode message data', 400, 40000 );
throw new AblyException( 'Could not JSON-decode message data' );
}

array_pop( $encodings );
} else if (strpos( $encoding, 'cipher+' ) === 0) {
if (!$this->cipherParams) {
throw new AblyEncryptionException( 'Could not decrypt message data, no cipherParams provided', 400, 40000 );
Log::e( 'Could not decrypt message data, no cipherParams provided' );
break;
}

$this->data = Crypto::decrypt( $this->data, $this->cipherParams );
$data = Crypto::decrypt( $this->data, $this->cipherParams );

if ($this->data === false) {
throw new AblyEncryptionException( 'Could not decrypt message data', 400, 40000 );
if ($data === false) {
Log::e( 'Could not decrypt message data' );
break;
}

$this->data = $data;
array_pop( $encodings );
}
}

$this->encoding = null;
$this->encoding = count( $encodings ) ? implode( '/', $encodings ) : null;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Models/ClientOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ClientOptions extends AuthOptions {
/**
* @var integer connection timeout after which a next fallback host is used
*/
public $hostTimeout = 10000;
public $hostTimeout = 15000;

/**
* @var string a class that should be used for making HTTP connections
Expand Down
20 changes: 20 additions & 0 deletions src/Models/ErrorInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
namespace Ably\Models;

/**
* Represents an error as returned from the Ably server
*/
class ErrorInfo {
/**
* @var int $code Exception code @see https://github.com/ably/ably-common/blob/master/protocol/errors.json
*/
public $code;
/**
* @var int $statusCode HTTP error code
*/
public $statusCode;
/**
* @var string $message Exception message
*/
public $message;
}
Loading