298 lines
9.3 KiB
PHP
298 lines
9.3 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Class to process sending requests and receiving responses.
|
|
*/
|
|
class ThumberClient {
|
|
/**
|
|
* The Thumber.co API subdomain.
|
|
*/
|
|
const ThumberServerHost = 'api.thumber.co';
|
|
|
|
/**
|
|
* The path for creating a new thumbnail.
|
|
*/
|
|
const ThumberServerCreatePath = '/create.json';
|
|
|
|
/**
|
|
* The path for GETting the user's current subscription info.
|
|
*/
|
|
const ThumberSubscriptionPath = '/subscription.json';
|
|
|
|
/**
|
|
* The path for GETting the supported MIME types.
|
|
*/
|
|
const ThumberServerMimeTypesPath = '/mime_types.json';
|
|
|
|
/**
|
|
* @var string The user agent to send HTTP requests as.
|
|
*/
|
|
protected $thumberUserAgent;
|
|
|
|
/**
|
|
* @var string UID for the user accessing the Thumber API.
|
|
*/
|
|
protected $uid;
|
|
|
|
/**
|
|
* @param $uid string UID for the user accessing the Thumber API.
|
|
*/
|
|
public function setUid($uid) {
|
|
$this->uid = $uid;
|
|
}
|
|
|
|
/**
|
|
* @var string The user secret assoicataed with the UID for the user
|
|
* accessing the Thumber API.
|
|
*/
|
|
protected $userSecret;
|
|
|
|
/**
|
|
* @param $userSecret string The user secret assoicataed with the UID for the user
|
|
* accessing the Thumber API.
|
|
*/
|
|
public function setUserSecret($userSecret) {
|
|
$this->userSecret = $userSecret;
|
|
}
|
|
|
|
/**
|
|
* @var string Fully-qualified system path to this file.
|
|
*/
|
|
private $thumberClientPath;
|
|
|
|
/**
|
|
* @var object The subscription object.
|
|
*/
|
|
private static $subscription;
|
|
|
|
/**
|
|
* @var array The supported MIME types.
|
|
*/
|
|
private static $mime_types;
|
|
|
|
/**
|
|
* @var ThumberClient Backs the getter.
|
|
*/
|
|
private static $instance;
|
|
|
|
/**
|
|
* @return ThumberClient The singleton instance.
|
|
*/
|
|
public static function getInstance() {
|
|
return isset( self::$instance ) ? self::$instance : ( self::$instance = new ThumberClient() );
|
|
}
|
|
|
|
/**
|
|
* Initialized class members.
|
|
*/
|
|
protected function __construct() {
|
|
$this->thumberUserAgent = 'Thumber Client 1.0 (PHP ' . phpversion() . '; ' . php_uname() . ')';
|
|
$this->thumberClientPath = dirname( __FILE__ ) . '/';
|
|
}
|
|
|
|
/**
|
|
* Sends the provided request to Thumber for processing.
|
|
*
|
|
* NOTE: Caller should consider testing file size against getSubscription()->file_size_limit to avoid unnecessary
|
|
* HTTP requests when the file will be rejected.
|
|
*
|
|
* @param ThumberThumbReq $req The request to be sent.
|
|
* @return array The results of sending the request.
|
|
*/
|
|
public function sendThumbRequest($req) {
|
|
if (!($req instanceof ThumberThumbReq)) {
|
|
$err = 'Request must be of type ThumberThumbReq.';
|
|
$this->handleError($err);
|
|
return array('error' => $err);
|
|
}
|
|
|
|
return $this->sendRequest($req, 'POST', self::ThumberServerCreatePath);
|
|
}
|
|
|
|
/**
|
|
* Processes the POST request, generating a ThumberResponse, validating, and passing the result to $callback.
|
|
* If not using client.php as the webhook, whoever receives webhook response should first invoke this method to
|
|
* validate response.
|
|
*/
|
|
public function receiveThumbResponse() {
|
|
include_once $this->thumberClientPath . 'thumb-response.php';
|
|
|
|
$json = stream_get_contents(fopen('php://input', 'r'));
|
|
$resp = ThumberThumbResp::parseJson($json);
|
|
|
|
if (is_null($resp)) {
|
|
$this->handleError('Failed to parse JSON in POST body: ' . $json);
|
|
return null;
|
|
}
|
|
|
|
if (!$resp->isValid($this->userSecret)) {
|
|
$this->handleError('Received invalid response: ' . $json);
|
|
return null;
|
|
}
|
|
|
|
// This method should be overridden in order to use response
|
|
return $resp;
|
|
}
|
|
|
|
/**
|
|
* @return object|null Returns an object with subscription information. Object includes the following:
|
|
* name, monthly_cost, watermark, direct_upload, thumbs_per_hr_limit, file_size_limit, and thumb_size_limit.
|
|
*/
|
|
public function getSubscription() {
|
|
include_once $this->thumberClientPath . 'base-transaction.php';
|
|
|
|
if (isset(self::$subscription)) {
|
|
return self::$subscription;
|
|
} else {
|
|
$resp = $this->sendRequest(new ThumberBaseTransaction(), 'GET', self::ThumberSubscriptionPath);
|
|
if (!array_key_exists('error', $resp)) {
|
|
self::$subscription = json_decode($resp['body']);
|
|
return self::$subscription;
|
|
} else {
|
|
$this->handleError('Failed to retrieve subscription: ' . $resp['body']);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the supported MIME types from Thumber.
|
|
* @return array The supported MIME types reported by the Thumber server.
|
|
*/
|
|
public function getMimeTypes() {
|
|
if (!isset(self::$mime_types)) {
|
|
$headers = array('Content-Type: application/json', 'Content-Length: 0');
|
|
$result = $this->sendToThumber('GET', self::getThumberUrl(self::ThumberServerMimeTypesPath), $headers);
|
|
self::$mime_types = !array_key_exists('error', $result) ? json_decode($result['body'], true) : array();
|
|
}
|
|
|
|
return self::$mime_types;
|
|
}
|
|
|
|
/**
|
|
* Sends the provided request to the API endpoint.
|
|
*
|
|
* @param ThumberBaseTransaction $req The request to be sent. UID, callback, and timestamp
|
|
* will be written by client. Additionally, nonce will be set if not already set.
|
|
* @param string $type The type of HTTP request (GET/POST/etc.)
|
|
* @param string $path The relative path on Thumber server to contact.
|
|
* @return array containing data about success of the cURL request.
|
|
*/
|
|
public function sendRequest($req, $type, $path) {
|
|
include_once $this->thumberClientPath . 'base-transaction.php';
|
|
|
|
if (!is_a($req, 'ThumberBaseTransaction')) {
|
|
$err = 'Request must be of type ThumberBaseTransaction.';
|
|
$this->handleError($err);
|
|
return array('error' => $err);
|
|
}
|
|
|
|
// whether we've changed any field, requiring recompute of checksum
|
|
$changed = false;
|
|
|
|
$timestamp = $req->getTimestamp();
|
|
if (empty($timestamp)) {
|
|
$req->setTimestamp(time());
|
|
$changed = true;
|
|
}
|
|
|
|
$uid = $req->getUid();
|
|
if (empty($uid)) {
|
|
$req->setUid($this->uid);
|
|
$changed = true;
|
|
}
|
|
|
|
$nonce = $req->getNonce();
|
|
if (empty($nonce)) {
|
|
$req->setNonce();
|
|
$changed = true;
|
|
}
|
|
|
|
$checksum = $req->getChecksum();
|
|
if ($changed || empty($checksum)) {
|
|
$req->setChecksum($req->computeChecksum($this->userSecret));
|
|
}
|
|
|
|
if (!$req->isValid($this->userSecret)) {
|
|
$err = 'Invalid request provided.';
|
|
$this->handleError($err);
|
|
return array('error' => $err);
|
|
}
|
|
|
|
$body = '';
|
|
if ($type == 'GET') {
|
|
$path .= '?' . $req->toQuery();
|
|
} else {
|
|
$body = $req->toJson();
|
|
}
|
|
|
|
$headers = array('Content-Type: application/json', 'Content-Length: ' . strlen($body));
|
|
$result = $this->sendToThumber($type, self::getThumberUrl($path), $headers, $body);
|
|
$result['nonce'] = !array_key_exists('error', $result) ? $req->getNonce() : '';
|
|
|
|
// caller should handle errors sensibly
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Sends cURL request to Thumber server.
|
|
* @param $type string GET or POST
|
|
* @param $url string The URL endpoint being targeted.
|
|
* @param $httpHeaders array The headers to be sent.
|
|
* @param $body string The POST body. Ignored if type is GET.
|
|
* @return array The result of the request.
|
|
*/
|
|
protected function sendToThumber($type, $url, $httpHeaders, $body = '') {
|
|
// open connection
|
|
$ch = curl_init();
|
|
|
|
curl_setopt($ch, CURLOPT_USERAGENT, $this->thumberUserAgent);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders);
|
|
if ($type == 'POST') {
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
|
}
|
|
|
|
// execute post, storing useful information about result
|
|
$response = curl_exec($ch);
|
|
$error = curl_error($ch);
|
|
$result = array (
|
|
'header' => '',
|
|
'body' => '',
|
|
'error' => '',
|
|
'http_code' => '',
|
|
'last_url' => ''
|
|
);
|
|
|
|
if ($error === '') {
|
|
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
|
|
|
$result['header'] = substr($response, 0, $header_size);
|
|
$result['body'] = substr($response, $header_size);
|
|
$result['http_code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$result['last_url'] = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
|
} else {
|
|
$result ['error'] = $error;
|
|
}
|
|
|
|
curl_close($ch);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* @param string $path The path at Thumber to generate URL from.
|
|
* @return string The full URL to the given relative path.
|
|
*/
|
|
private static function getThumberUrl($path) {
|
|
return 'http://' . self::ThumberServerHost . $path;
|
|
}
|
|
|
|
/**
|
|
* @param $err string Fires on fatal error.
|
|
*/
|
|
protected function handleError($err) {
|
|
echo $err;
|
|
}
|
|
} |