Last active
April 20, 2020 12:36
-
-
Save Driver86/913478cfa8472406078f to your computer and use it in GitHub Desktop.
uCoz API module for PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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