private function logMessages() { Log::v('This is a test verbose message.'); Log::d('This is a test debug message.'); Log::w('This is a test warning.'); Log::e('This is a test error.'); }
/** * Executes a cURL request * @param string $method HTTP method (GET, POST, PUT, DELETE, ...) * @param string $url Absolute URL to make a request on * @param array $headers HTTP headers to send * @param array|string $params Array of parameters to submit or a JSON string * @throws AblyRequestException if the request fails * @throws AblyRequestTimeoutException if the request times out * @return array with 'headers' and 'body' fields, body is automatically decoded */ public function request($method, $url, $headers = [], $params = []) { $ch = $this->curl->init($url); $this->curl->setOpt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->connectTimeout); $this->curl->setOpt($ch, CURLOPT_TIMEOUT_MS, $this->requestTimeout); if (!empty($params)) { if (is_array($params)) { $paramsQuery = http_build_query($params); if ($method == 'GET') { if ($paramsQuery) { $url .= '?' . $paramsQuery; } $this->curl->setOpt($ch, CURLOPT_URL, $url); } else { if ($method == 'POST') { $this->curl->setOpt($ch, CURLOPT_POST, true); $this->curl->setOpt($ch, CURLOPT_POSTFIELDS, $paramsQuery); } else { $this->curl->setOpt($ch, CURLOPT_CUSTOMREQUEST, $method); $this->curl->setOpt($ch, CURLOPT_POSTFIELDS, $paramsQuery); } } } else { if (is_string($params)) { // json or msgpack if ($method == 'GET') { } else { if ($method == 'POST') { $this->curl->setOpt($ch, CURLOPT_POST, true); } else { $this->curl->setOpt($ch, CURLOPT_CUSTOMREQUEST, $method); } } $this->curl->setOpt($ch, CURLOPT_POSTFIELDS, $params); if ($this->postDataFormat == 'json') { array_push($headers, 'Content-Type: application/json'); } } else { throw new AblyRequestException('Unknown $params format'); } } } if (!empty($headers)) { $this->curl->setOpt($ch, CURLOPT_HTTPHEADER, $headers); } $this->curl->setOpt($ch, CURLOPT_RETURNTRANSFER, true); if (Log::getLogLevel() >= Log::VERBOSE) { $this->curl->setOpt($ch, CURLOPT_VERBOSE, true); } $this->curl->setOpt($ch, CURLOPT_HEADER, true); // return response headers Log::d('cURL command:', $this->curl->getCommand($ch)); $raw = $this->curl->exec($ch); $info = $this->curl->getInfo($ch); $err = $this->curl->getErrNo($ch); $errmsg = $err ? $this->curl->getError($ch) : ''; $this->curl->close($ch); if ($err) { // a connection error has occured (no data received) Log::e('cURL error:', $err, $errmsg); throw new AblyRequestException('cURL error: ' . $errmsg, 50003, 500); } $resHeaders = substr($raw, 0, $info['header_size']); $body = substr($raw, $info['header_size']); $decodedBody = json_decode($body); $response = ['headers' => $resHeaders, 'body' => $decodedBody ? $decodedBody : $body]; Log::v('cURL request response:', $info['http_code'], $response); if ($info['http_code'] < 200 || $info['http_code'] >= 300) { $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, $ablyCode, $info['http_code'], $response); } return $response; }
/** * Create a signed token request based on known credentials * and the given token params. This would typically be used if creating * signed requests for submission by another client. * @param \Ably\Models\TokenParams $tokenParams * @param \Ably\Models\AuthOptions $authOptions * @return \Ably\Models\TokenRequest A signed token request */ public function createTokenRequest($tokenParams = [], $authOptions = []) { $tokenClientId = $this->defaultTokenParams->clientId; if (!empty($this->defaultAuthOptions->clientId)) { $tokenClientId = $this->defaultAuthOptions->clientId; } if (array_key_exists('clientId', $authOptions)) { $tokenClientId = $authOptions['clientId']; } if (array_key_exists('clientId', $tokenParams)) { $tokenClientId = $tokenParams['clientId']; } $authOptions = new AuthOptions(array_merge($this->defaultAuthOptions->toArray(), $authOptions)); $tokenParams = new TokenParams(array_merge($this->defaultTokenParams->toArray(), $tokenParams)); $tokenParams->clientId = $tokenClientId; $keyParts = explode(':', $authOptions->key); if (count($keyParts) != 2) { Log::e('Auth::createTokenRequest', "Can't create signed token request, invalid key specified"); throw new AblyException('Invalid key specified', 40101, 401); } $keyName = $keyParts[0]; $keySecret = $keyParts[1]; $tokenRequest = new TokenRequest($tokenParams); if (!empty($tokenRequest->keyName) && $tokenRequest->keyName != $keyName) { throw new AblyException('Incompatible keys specified', 40102, 401); } else { $tokenRequest->keyName = $keyName; } if ($authOptions->queryTime) { $tokenRequest->timestamp = sprintf("%.0f", $this->ably->time()); } else { if (empty($tokenRequest->timestamp)) { $tokenRequest->timestamp = sprintf("%.0f", $this->ably->systemTime()); } } // note: sprintf converts floating point numbers to plain integers (without scientific notation) // regardless of the "precision" php.ini setting if (empty($tokenRequest->clientId)) { $tokenRequest->clientId = $authOptions->clientId; } if (empty($tokenRequest->nonce)) { $tokenRequest->nonce = md5(microtime(true) . mt_rand()); } $signText = implode("\n", [empty($tokenRequest->keyName) ? '' : $tokenRequest->keyName, empty($tokenRequest->ttl) ? '' : $tokenRequest->ttl, empty($tokenRequest->capability) ? '' : $tokenRequest->capability, empty($tokenRequest->clientId) ? '' : $tokenRequest->clientId, empty($tokenRequest->timestamp) ? '' : $tokenRequest->timestamp, empty($tokenRequest->nonce) ? '' : $tokenRequest->nonce]) . "\n"; if (empty($tokenRequest->mac)) { $tokenRequest->mac = base64_encode(hash_hmac('sha256', $signText, $keySecret, true)); } return $tokenRequest; }
/** * Does a HTTP request backed up by fallback servers */ protected function requestWithFallback($method, $path, $headers = [], $params = [], $attempt = 0) { try { if ($attempt == 0) { // using default host $server = ($this->options->tls ? 'https://' : 'http://') . $this->options->restHost; } else { // using a fallback host Log::d('Connection failed, attempting with fallback server #' . $attempt); // attempt 1 uses fallback host with index 0 $server = ($this->options->tls ? 'https://' : 'http://') . $this->options->fallbackHosts[$attempt - 1]; } return $this->http->request($method, $server . $path, $headers, $params); } catch (AblyRequestException $e) { if ($e->getCode() >= 50000) { if ($attempt < min($this->options->httpMaxRetryCount, count($this->options->fallbackHosts))) { return $this->requestWithFallback($method, $path, $headers, $params, $attempt + 1); } else { Log::e('Failed to connect to server and all of the fallback servers.'); throw $e; } } throw $e; // other error code than timeout, rethrow exception } }
/** * Decodes message's data field according to encoding * @throws AblyException */ protected function decode() { $this->originalData = $this->data; $this->originalEncoding = $this->encoding; if (!empty($this->encoding)) { $encodings = explode('/', $this->encoding); foreach (array_reverse($encodings) as $encoding) { if ($encoding == 'base64') { $this->data = base64_decode($this->data); if ($this->data === false) { 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'); } array_pop($encodings); } else { if (strpos($encoding, 'cipher+') === 0) { if (!$this->cipherParams) { Log::e('Could not decrypt message data, no cipherParams provided'); break; } $data = Crypto::decrypt($this->data, $this->cipherParams); if ($data === false) { Log::e('Could not decrypt message data'); break; } $this->data = $data; array_pop($encodings); } } } } $this->encoding = count($encodings) ? implode('/', $encodings) : null; } }