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; }
/** * Request a new token. * @param array|null $tokenParams Requested token parameters * @param array|null $authOptions Overridable auth options, if you don't wish to use the default ones * @param \Ably\Models\ClientOptions|array $options * @throws \Ably\Exceptions\AblyException * @return \Ably\Models\TokenDetails The new token */ public function requestToken($tokenParams = [], $authOptions = []) { // token clientId priority: // $tokenParams->clientId overrides $authOptions->tokenId overrides $this->defaultAuthOptions->clientId overrides $this->defaultTokenParams->clientId $tokenClientId = $this->defaultTokenParams->clientId; if (!empty($this->defaultAuthOptions->clientId)) { $tokenClientId = $this->defaultAuthOptions->clientId; } // provided authOptions may override clientId, even with a null value if (array_key_exists('clientId', $authOptions)) { $tokenClientId = $authOptions['clientId']; } // provided tokenParams may override clientId, even with a null value if (array_key_exists('clientId', $tokenParams)) { $tokenClientId = $tokenParams['clientId']; } // merge provided auth options with defaults $authOptionsMerged = new AuthOptions(array_merge($this->defaultAuthOptions->toArray(), $authOptions)); $tokenParamsMerged = new TokenParams(array_merge($this->defaultTokenParams->toArray(), $tokenParams)); $tokenParamsMerged->clientId = $tokenClientId; // get a signed token request $signedTokenRequest = null; if (!empty($authOptionsMerged->authCallback)) { Log::d('Auth::requestToken:', 'using token auth with auth_callback'); $callback = $authOptionsMerged->authCallback; $data = $callback($tokenParamsMerged); // returned data can be either a signed TokenRequest or TokenDetails or just a token string if (is_a($data, '\\Ably\\Models\\TokenRequest')) { $signedTokenRequest = $data; } else { if (is_a($data, '\\Ably\\Models\\TokenDetails')) { return $data; } else { if (is_string($data)) { return new TokenDetails($data); } else { Log::e('Auth::requestToken:', 'Invalid response from authCallback, expecting signed TokenRequest or TokenDetails or a token string'); throw new AblyException('Invalid response from authCallback'); } } } } elseif (!empty($authOptionsMerged->authUrl)) { Log::d('Auth::requestToken:', 'using token auth with auth_url'); $data = $this->ably->http->request($authOptionsMerged->authMethod, $authOptionsMerged->authUrl, $authOptionsMerged->authHeaders ?: [], array_merge($authOptionsMerged->authParams ?: [], $tokenParamsMerged->toArray())); $data = $data['body']; if (is_string($data)) { return new TokenDetails($data); // assuming it's a token string } else { if (is_object($data)) { if (!empty($data->issued)) { // assuming it's a token return new TokenDetails($data); } else { if (!empty($data->mac)) { // assuming it's a signed token request $signedTokenRequest = new TokenRequest($data); } else { Log::e('Auth::requestToken:', 'Invalid response from authURL, expecting JSON representation of signed TokenRequest or TokenDetails'); throw new AblyException('Invalid response from authURL'); } } } else { Log::e('Auth::requestToken:', 'Invalid response from authURL, expecting token string or JSON representation of signed TokenRequest or TokenDetails'); throw new AblyException('Invalid response from authURL'); } } } elseif (!empty($authOptionsMerged->key)) { Log::d('Auth::requestToken:', 'using token auth with client-side signing'); $signedTokenRequest = $this->createTokenRequest($tokenParams, $authOptions); } 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', 40101, 401); } // do the request $keyName = $signedTokenRequest->keyName; if (empty($keyName)) { throw new AblyException('No keyName specified in the TokenRequest'); } $res = $this->ably->post("/keys/{$keyName}/requestToken", $headers = [], $params = json_encode($signedTokenRequest->toArray()), $returnHeaders = false, $authHeaders = false); 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', 40100, 401); } return new TokenDetails($res); }
/** * 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 } }