Skip to content

Instantly share code, notes, and snippets.

@Driver86
Last active April 20, 2020 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Driver86/913478cfa8472406078f to your computer and use it in GitHub Desktop.
Save Driver86/913478cfa8472406078f to your computer and use it in GitHub Desktop.
uCoz API module for PHP
<?php
/**
* Набор методов для запроса к API uCoz.
*
* Пример использования на PHP-хостинге uCoz:
* <code>
* <?php
* $___notjson = 1;
* // Подключаем класс для работы с uAPI:
* require 'uAPI.php';
* // Создаём объект, передав в него свои параметры oAuth:
* $uAPI = new uAPI(array(
* 'oauth_consumer_key' => '???', // Consumer key
* 'oauth_consumer_secret' => '???', // Consumer secret
* 'oauth_token' => '???', // oAuth token
* 'oauth_token_secret' => '???', // oAuth token secret
* 'cache_time' => 3600, // Время жизни кэша, в секундах (по-умолчанию - 0 (т.е. кэш отключён))
* 'cache_file' => 'uAPI.cache', // Путь до файла с кэшем (по-умолчанию - 'uAPI.cache')
* 'cache_compress' => true, // Сжимать кэш или нет (по-умолчанию - true)
* 'domain' => 'example.com', // Домен uAPI (по-умолчанию - $_SERVER['HTTP_HOST'])
* ));
* // Запрос к uAPI имеет вид: $uAPI->метод(url, дополнительные_параметры), например:
* $response = $uAPI->get('/blog', array('page' => 2));
* // Данные возвращаются в виде массива PHP:
* // см. http://api.ucoz.net
* print_r($response);
* // Очистка кеша
* $uAPI->clearCache();
* ?>
* </code>
*
* @author Sergey Driver86 Pugovkin <sergey@pugovk.in>
* @version 1.4
*/
class uAPI
{
/**
* Массив с настройками.
*
* @var array
*/
protected $config;
/**
* Объект PDO для работы с кэшем.
*
* @var PDO
*/
protected $cacheDb;
/**
* Массив с обязательными параметрами (oAuth), передаваемыми при запросе к API.
*
* @var array
*/
protected $oAuthParams;
/**
* Конструктор класса.
*
* @param array $config Настройки.
*/
function __construct($config = array())
{
$config['oauth_consumer_key'] = isset($config['oauth_consumer_key']) ? strval($config['oauth_consumer_key']) : '';
$config['oauth_consumer_secret'] = isset($config['oauth_consumer_secret']) ? strval($config['oauth_consumer_secret']) : '';
$config['oauth_token'] = isset($config['oauth_token']) ? strval($config['oauth_token']) : '';
$config['oauth_token_secret'] = isset($config['oauth_token_secret']) ? strval($config['oauth_token_secret']) : '';
$config['cache_time'] = isset($config['cache_time']) ? (int)$config['cache_time'] : 0;
$config['cache_file'] = isset($config['cache_file']) ? strval($config['cache_file']) : (dirname(__FILE__) . '/uAPI.cache');
$config['cache_compress'] = !empty($config['cache_compress']);
$config['domain'] = isset($config['domain']) ? strval($config['domain']) : $_SERVER['HTTP_HOST'];
$this->config = $config;
if ($this->config['cache_time'] > 0) {
try {
$this->cacheDb = new PDO('sqlite:' . $this->config['cache_file']);
} catch (PDOException $e) {
trigger_error($e->getMessage(), E_USER_WARNING);
$this->cacheDb = null;
}
if (isset($this->cacheDb)) {
$this->cacheDb->exec('CREATE TABLE IF NOT EXISTS `cached` (`id` INTEGER NOT NULL PRIMARY KEY, `timestamp` INTEGER NOT NULL, `data` BLOB NOT NULL, `compressed` INTEGER NOT NULL)');
$this->cacheDb->exec('CREATE INDEX IF NOT EXISTS `timestamp` ON `cached` (`timestamp`)');
}
}
$this->oAuthParams = array(
'oauth_version' => '1.0',
'oauth_timestamp' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_consumer_key' => $this->config['oauth_consumer_key'],
'oauth_token' => $this->config['oauth_token'],
// Эти параметры устанавливаются непосредственно при каждом запросе:
// 'oauth_signature' => ,
// 'oauth_nonce' => ,
);
}
/**
* Создание уникального идентификатора (ID) из параметров запроса для использования в кэшировании.
*
* @param string $url URL запроса, например '/blog'.
* @param array $data Массив с параметрами запроса, например array('page' => 146).
* @return int ID кэша.
*/
protected function getCacheId($url, $data = array())
{
ksort($data, SORT_STRING);
$hash = md5($url . serialize($data) . $this->config['oauth_token_secret']);
return intval(
(intval(substr($hash, 0, 7), 16) % 7 + 1) . substr($hash, 7, PHP_INT_SIZE * 2 - 1),
16
);
}
/**
* Запрос к кэшу.
*
* @param string $id ID кэша.
* @return array|null Массив данных из кэша, или NULL при их отсутствии в кэше.
*/
protected function getCache($id)
{
if (!isset($this->cacheDb)) {
return null;
}
if ($this->config['cache_time'] > 0) {
$query = $this->cacheDb->prepare('SELECT * FROM `cached` WHERE `id` = ? AND `timestamp` > ?');
$result = array();
$query->execute(array($id, time() - $this->config['cache_time'])) and $result = $query->fetch(PDO::FETCH_ASSOC);
$query->closeCursor();
if (!empty($result)) {
return unserialize($result['compressed'] ? gzinflate($result['data']) : $result['data']);
}
}
return null;
}
/**
* Сохранение в кэше.
*
* @param string $id ID кэша.
* @param array $data Массив данных.
* @return bool TRUE в случае успеха, иначе FALSE.
*/
protected function setCache($id, $data)
{
if (!isset($this->cacheDb)) {
return false;
}
if ($this->config['cache_time'] > 0) {
$timestamp = time();
$data = serialize($data);
if ($this->config['cache_compress']) {
$data = gzdeflate($data, 9);
}
$query = $this->cacheDb->prepare('REPLACE INTO `cached` (`id`, `timestamp`, `data`, `compressed`) VALUES (?, ?, ?, ?)');
$result = $query->execute(array($id, $timestamp, $data, (int)$this->config['cache_compress']));
$query->closeCursor();
return $result;
}
return true;
}
/**
* Очистка кэша.
*
* @param int $id ID кэша. Если не указан, то удаляется весь кэш.
* @return bool TRUE в случае успеха, иначе FALSE.
*/
public function deleteCache($id = -1)
{
if (!isset($this->cacheDb)) {
return false;
}
if ($id < 0) {
$query = $this->cacheDb->prepare('DELETE FROM `cached`');
$result = $query->execute();
} else {
$query = $this->cacheDb->prepare('DELETE FROM `cached` WHERE `id` = ?');
$result = $query->execute(array($id));
}
$query->closeCursor();
return $result;
}
/**
* Callback-функция для array_map():
* значения массива (данные для отправки) меняются таким образом,
* что параметры, представляющие файл для отправки, заменяются на имя файла.
* Необходимо для создания подписи запроса.
*
* @param string|object $value Значение массива ("@file" или CURLFile).
* @return string Имя файла, либо значение без изменений.
*/
protected function fileNamesOnly($value)
{
if (function_exists('curl_file_create')) {
if (is_object($value) and get_class($value) == 'CURLFile') {
return $value->getPostFilename();
}
} else {
if (substr($value, 0, 1) == '@') {
return basename(substr($value, 1));
}
}
return $value;
}
/**
* Создание подписи запроса.
*
* @param string $method Метод запроса, например 'GET'.
* @param string $url Абсолютный URL запроса (без параметров), например 'http://examplecom/uapi/blog'.
* @param array $params Массив со всеми параметрами (включая OAuth), передаваемыми при запросе к API.
* @return string Подпись запроса.
*/
protected function getSignature($method, $url, $params)
{
unset($params['oauth_signature']);
ksort($params);
$baseString = strtoupper($method) . '&' . urlencode($url) . '&' . urlencode(strtr(http_build_query($params), array('+' => '%20')));
return urlencode(base64_encode(hash_hmac('sha1', $baseString, $this->config['oauth_consumer_secret'] . '&' . $this->config['oauth_token_secret'], true)));
}
/**
* Запрос к API методом GET.
*
* @param string $url Относительный URL запроса, например '/blog'.
* @param array $data Массив с параметрами запроса, например array('page' => 146).
* @return array|null Массив с ответом, либо NULL, в случае ошибки.
*/
public function get($url, $data = array())
{
$cacheId = $this->getCacheId($url, $data);
$cache = $this->getCache($cacheId);
if ($cache !== null) {
return $cache;
}
$method = strtoupper(__FUNCTION__);
$url = 'http://' . $this->config['domain'] . '/uapi/' . ltrim(strtolower($url), '/');
$this->oAuthParams['oauth_nonce'] = md5(microtime() . mt_rand());
$params = $this->oAuthParams + $data;
$queryData = array(
'oauth_signature' => $this->getSignature(
$method,
$url,
$params
)
) + $params;
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_URL, $url . '?' . http_build_query($queryData));
$result = json_decode(curl_exec($curl), true);
curl_close($curl);
if (count($result) == 1 and isset($result['error']['code']) and isset($result['error']['msg'])) {
trigger_error("{$result['error']['msg']} ({$result['error']['code']})", E_USER_WARNING);
return null;
}
$this->setCache($cacheId, $result);
return $result;
}
/**
* Запрос к API методом POST.
*
* @param string $url Относительный URL запроса, например '/blog'.
* @param array $data Массив с параметрами запроса, например array('page' => 146).
* @return array|null Массив с ответом, либо NULL, в случае ошибки.
*/
public function post($url, $data)
{
$cacheId = $this->getCacheId($url, $data);
$cache = $this->getCache($cacheId);
if ($cache !== null) {
return $cache;
}
$method = strtoupper(__FUNCTION__);
$url = 'http://' . $this->config['domain'] . '/uapi/' . ltrim(strtolower($url), '/');
$this->oAuthParams['oauth_nonce'] = md5(microtime() . mt_rand());
$params = $this->oAuthParams + $data;
$queryData = array(
'oauth_signature' => $this->getSignature(
$method,
$url,
array_map(array($this, 'fileNamesOnly'), $params)
)
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_URL, $url . '?' . http_build_query($queryData));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
$result = json_decode(curl_exec($curl), true);
curl_close($curl);
if (count($result) == 1 and isset($result['error']['code']) and isset($result['error']['msg'])) {
trigger_error("{$result['error']['msg']} ({$result['error']['code']})", E_USER_WARNING);
return null;
}
$this->setCache($cacheId, $result);
return $result;
}
/**
* Запрос к API методом PUT.
*
* @param string $url Относительный URL запроса, например '/blog'.
* @param array $data Массив с параметрами запроса, например array('page' => 146).
* @return array|null Массив с ответом, либо NULL, в случае ошибки.
*/
public function put($url, $data)
{
$cacheId = $this->getCacheId($url, $data);
$cache = $this->getCache($cacheId);
if ($cache !== null) {
return $cache;
}
$method = strtoupper(__FUNCTION__);
$url = 'http://' . $this->config['domain'] . '/uapi/' . ltrim(strtolower($url), '/');
$this->oAuthParams['oauth_nonce'] = md5(microtime() . mt_rand());
$params = $this->oAuthParams + $data;
$queryData = array(
'oauth_signature' => $this->getSignature(
$method,
$url,
array_map(array($this, 'fileNamesOnly'), $params)
)
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_URL, $url . '?' . http_build_query($queryData));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
$result = json_decode(curl_exec($curl), true);
curl_close($curl);
if (count($result) == 1 and isset($result['error']['code']) and isset($result['error']['msg'])) {
trigger_error("{$result['error']['msg']} ({$result['error']['code']})", E_USER_WARNING);
return null;
}
$this->setCache($cacheId, $result);
return $result;
}
/**
* Запрос к API методом DELETE.
*
* @param string $url Относительный URL запроса, например '/blog'.
* @param array $data Массив с параметрами запроса, например array('page' => 146).
* @return array|null Массив с ответом, либо NULL, в случае ошибки.
*/
public function delete($url, $data)
{
$cacheId = $this->getCacheId($url, $data);
$cache = $this->getCache($cacheId);
if ($cache !== null) {
return $cache;
}
$method = strtoupper(__FUNCTION__);
$url = 'http://' . $this->config['domain'] . '/uapi/' . ltrim(strtolower($url), '/');
$this->oAuthParams['oauth_nonce'] = md5(microtime() . mt_rand());
$params = $this->oAuthParams + $data;
$queryData = array(
'oauth_signature' => $this->getSignature(
$method,
$url,
$params
)
) + $params;
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_URL, $url . '?' . http_build_query($queryData));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
$result = json_decode(curl_exec($curl), true);
curl_close($curl);
if (count($result) == 1 and isset($result['error']['code']) and isset($result['error']['msg'])) {
trigger_error("{$result['error']['msg']} ({$result['error']['code']})", E_USER_WARNING);
return null;
}
$this->setCache($cacheId, $result);
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment