PHP Client
Introduction
The Client encapsulates features such as request signing, obtaining access_token, refreshing access_token, etc. With the PHP Client, you can quickly initiate requests to the FastMoss API. NOTE: cacheToken and getCachedToken methods must be implemented.
request example
PHP
<?php
use FastMossClient;
$client = new FastMossClient('client_id', 'client_secret');
$result = $client->test(['hello'=>'world'])PHP Client Code:
php
<?php
// FastMossClient.php - A PHP client for FastMoss API
/**
* FastMossClient provides a complete implementation for:
* - Token management (acquisition and refresh)
* - API request signing
* - Local token caching
* - Standardized API calls
*
* Example usage:
* $client = new FastMossClient("your_id", "your_secret");
* $response = $client->doApiCall("/v1/videos", ["page" => 1]);
*
* NOTE: cacheToken and getCachedToken methods must be implemented.
*/
class FastMossError extends Exception
{
// Base exception for FastMoss API errors
}
class FastMossClient
{
private $clientId;
private $clientSecret;
private $baseUrl;
private $timeout;
private $httpClient;
/**
* Initialize the FastMoss API client
*
* @param string $clientId API client identifier
* @param string $clientSecret API client secret key
* @param string $baseUrl Base API URL (defaults to test environment)
* @param int $timeout Request timeout in seconds
*/
public function __construct(
string $clientId,
string $clientSecret,
string $baseUrl = "https://openapi.test.fastmoss.com",
int $timeout = 15
) {
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->baseUrl = rtrim($baseUrl, "/");
$this->timeout = $timeout;
$this->httpClient = curl_init();
// Configure logging
error_log(date('Y-m-d H:i:s') . " - FastMossClient - INFO - Initialized client\n", 3, 'fastmoss.log');
}
/**
* Request a new access token from FastMoss API
*
* @return array Token information
* @throws FastMossError
*/
private function getNewToken(): array
{
$url = $this->baseUrl . "/v1/token";
$payload = [
"client_id" => $this->clientId,
"client_secret" => $this->clientSecret
];
try {
$response = $this->makeHttpRequest($url, $payload, "POST");
$responseData = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new FastMossError("Failed to decode token response");
}
if ($responseData["code"] === 0) {
return $responseData["data"] ?? [];
} else {
$errorMsg = $responseData["message"] ?? "Unknown error";
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Token request failed: $errorMsg\n", 3, 'fastmoss.log');
throw new FastMossError($errorMsg);
}
} catch (Exception $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Token request exception: {$e->getMessage()}\n", 3, 'fastmoss.log');
throw new FastMossError("Token request failed: {$e->getMessage()}");
}
}
/**
* Refresh an expired access token
*
* @param string $refreshToken The refresh token
* @return array New token information
* @throws FastMossError
*/
private function refreshToken(string $refreshToken): array
{
$url = $this->baseUrl . "/v1/refreshToken";
$payload = [
"client_id" => $this->clientId,
"refresh_token" => $refreshToken
];
try {
$response = $this->makeHttpRequest($url, $payload, "POST");
$responseData = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new FastMossError("Failed to decode refresh token response");
}
if ($responseData["code"] === 0) {
return $responseData["data"] ?? [];
} else {
$errorMsg = $responseData["message"] ?? "Unknown error";
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Token refresh failed: $errorMsg\n", 3, 'fastmoss.log');
throw new FastMossError($errorMsg);
}
} catch (Exception $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Token refresh exception: {$e->getMessage()}\n", 3, 'fastmoss.log');
throw new FastMossError("Token refresh failed: {$e->getMessage()}");
}
}
/**
* Retrieve cached token from local storage
*
* @return ?array Cached token if available, null otherwise
*/
private function getCachedToken(): ?array
{
// TODO: Implement actual storage/retrieval logic
// $key = 'fm_token:' . $this->clientId;
// $cachedData = Cache::get($key);
// if(empty($cachedData)) {
// return null;
// }
//return json_decode($cachedData,true);
return null;
}
/**
* Cache token data in local storage
*
* @param array $tokenData Token information to cache
* @return bool True if caching succeeded
*/
private function cacheToken(array $tokenData): bool
{
// TODO: Implement actual storage logic
// $key = 'fm_token:' . $this->clientId;
// Cache::set($key,json_encode($tokenData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $tokenData['refresh_expires_in'] ?? 86400)
return true;
}
/**
* Check if token is still valid
*
* @param array $tokenData Token information
* @return bool True if valid
*/
private function isTokenValid(array $tokenData): bool
{
$expiresAt = $tokenData["expire_at"] ?? 0;
$currentTime = time();
return $expiresAt > $currentTime + 600; // 10 minute buffer
}
/**
* Check if refresh token is still valid
*
* @param array $tokenData Token information
* @return bool True if valid
*/
private function isRefreshTokenValid(array $tokenData): bool
{
$refreshExpiresAt = $tokenData["refresh_expire_at"] ?? 0;
$currentTime = time();
return $refreshExpiresAt > $currentTime + 600; // 10 minute buffer
}
/**
* Get a valid access token, using cache if available
*
* @return array Token information
* @throws FastMossError
*/
public function getToken(): array
{
$tokenData = $this->getCachedToken();
if ($tokenData) {
if ($this->isTokenValid($tokenData)) {
return $tokenData;
} elseif ($this->isRefreshTokenValid($tokenData)) {
try {
$newToken = $this->refreshToken($tokenData["refresh_token"]);
$this->cacheToken($newToken);
return $newToken;
} catch (FastMossError $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - WARNING - Token refresh failed, getting new token\n", 3, 'fastmoss.log');
}
}
}
try {
$newToken = $this->getNewToken();
$this->cacheToken($newToken);
return $newToken;
} catch (FastMossError $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Failed to get new token\n", 3, 'fastmoss.log');
throw new FastMossError("Failed to acquire valid token: {$e->getMessage()}");
}
}
/**
* Generate API request signature
*
* @param string $uri API endpoint URI
* @param string $jsonStr JSON string of request payload
* @return string SHA256 signature
*/
private function generateSignature(string $uri, string $jsonStr): string
{
$signData = "{$this->clientSecret}|{$uri}|{$jsonStr}|{$this->clientSecret}";
return hash('sha256', $signData);
}
/**
* Make HTTP request using curl
*
* @param string $url Request URL
* @param array $postData Request payload
* @param string $method HTTP method
* @return string Response body
* @throws Exception
*/
private function makeHttpRequest(string $url, array $postData, string $method): string
{
$ch = $this->httpClient;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json; charset=utf-8'
]);
if ($method === "POST") {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false || $httpCode >= 400) {
$error = curl_error($ch) ?: "HTTP $httpCode";
throw new Exception("Request failed: $error");
}
return $response;
}
/**
* Make an authenticated API call to FastMoss
*
* @param string $uri API endpoint URI
* @param array $postData Request parameters
* @param string $method HTTP method
* @return array API response data
* @throws FastMossError
*/
public function doApiCall(string $uri, array $postData, string $method = "POST"): array
{
try {
$tokenInfo = $this->getToken();
$accessToken = $tokenInfo["access_token"] ?? null;
if (!$accessToken) {
throw new FastMossError("Access token not available");
}
$postDataStr = json_encode($postData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$signature = $this->generateSignature($uri, $postDataStr);
$timestamp = time();
$url = $this->baseUrl . $uri . "?" . http_build_query([
"access_token" => $accessToken,
"sign" => $signature,
"client_id" => $this->clientId,
"timestamp" => $timestamp,
"signature_version" => 2
]);
$response = $this->makeHttpRequest($url, $postData, $method);
$responseData = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new FastMossError("Failed to decode API response");
}
return $responseData;
} catch (Exception $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - API request failed: {$e->getMessage()}\n", 3, 'fastmoss.log');
throw new FastMossError("API request failed: {$e->getMessage()}");
}
}
/**
* FastMoss Test API
*
* @param array $params Query parameters
* @return array Video list data
* @throws FastMossError
*/
public function test(array $params): array
{
try {
$response = $this->doApiCall("/test", $params);
error_log(date('Y-m-d H:i:s') . " - FastMossClient - INFO - Successfully called test\n", 3, 'fastmoss.log');
return $response;
} catch (FastMossError $e) {
error_log(date('Y-m-d H:i:s') . " - FastMossClient - ERROR - Failed to call test: {$e->getMessage()}\n", 3, 'fastmoss.log');
throw $e;
}
}
}