14Июнь/11Off
Защищённый запрос к ВКонтакте API

Класс из GMFramework, с помощью которого можно осуществлять запросы к ВКонтакте API.
Для обеспечения безопасности запроса используется защищенный ключ приложения. Подразумевается, что он сохранён в константе SECURE_CODE.
Для выполнения запросов к скриптам ВКонтакте используется модуль PHP cURL, для обработки ответа JSON. От использования XML-формата я отказался, поэтому он больше не поддерживается.
/**
* Защищённый запрос к api ВКонтакте
* @package ru.vbinc.gm.framework.VKontakte
* @author GreyMag
* @copyright 2009
* @version 1.6
*/
class SecureRequest
{
/**
* Сообщение об ошибке
*/
public $error;
/**
* Номер ошибки
*/
public $errno;
/**
* Посланные поля
*/
public $requestFields;
private $_secureCode; // защищенный ключ
private $_apiId; // идентификатор приложения
private $_method; // название метода API из общего списка функций
private $_parameters = array(); // массив передаваемых параметров
private $_v = '2.0'; // версия API - необязательный параметр
private $_format; // формат возвращаемых данных – XML или JSON. По умолчанию JSON (на ВК по умолчанию XML) - необязательный параметр
private $_requestUrl = 'http://api.vkontakte.ru/api.php'; // url для запроса
private $_testMode = false; // тестовый режим
// список защищёных методов
/**
* Метод отправляет уведомление пользователю
*/
const SEND_NOTIFICATION = 'secure.sendNotification';
/**
* Метод сохраняет строку статуса приложения
* для последующего вывода в общем списке приложений на странице пользоваетеля
*/
const SAVE_APP_STATUS = 'secure.saveAppStatus';
/**
* Метод возвращает платежный баланс приложения
*/
const GET_APP_BALANCE = 'secure.getAppBalance';
/**
* Метод возвращает баланс пользователя на счету приложения
*/
const GET_BALANCE = 'secure.getBalance';
/**
* Метод списывает голоса со счета пользователя на счет приложения
*/
const WITHDRAW_VOTES = 'secure.withdrawVotes';
/**
* Метод возвращает историю транзакций внутри приложения
*/
const GET_TRANSACTIONS_HISTORY = 'secure.getTransactionsHistory';
/**
* Таймаут между запросами ( не больше трех в секунду )
*/
const KONTAKT_REQUEST_DELAY = .3;
/**
* формат возвращаемых данных - xml
* @var String
*/
const FORMAT_XML = 'XML';
/**
* формат возвращаемых данных - json
* @var String
*/
const FORMAT_JSON = 'JSON';
public function __construct( $apiId, $testMode = false )
{
$this->_apiId = $apiId;
if( defined( 'SECURE_CODE' ) ) $this->_secureCode = SECURE_CODE;
$this->_format = self::FORMAT_JSON;
$this->_parameters['api_id'] = $this->_apiId;
$this->_parameters['v'] = $this->_v;
$this->_parameters['format'] = $this->_format;
if( $testMode )
{
$this->_testMode = true;
$this->_parameters['test_mode'] = '1';
}
}
/**
* SecureRequest::request()
* Отправка запроса на ВКонтакте
* @param mixed $method Название метода
* @param array $parameters Массив передаваемых параметров со значениями
* @return Объект ответа с ВКонтакте
*/
public function request( $method, $parameters = array() )
{
$this->_parameters['method'] = $method;
if( is_array( $parameters ) )
$this->_parameters = array_merge( $this->_parameters, $parameters );
$this->_parameters['timestamp'] = $this->getTimestamp();
$this->_parameters['random'] = BaseString::randomStr();
$queryString = $this->createQueryString();
$curl = curl_init();
curl_setopt( $curl, CURLOPT_URL, $this->_requestUrl );
curl_setopt( $curl, CURLOPT_POST, 1 );
curl_setopt( $curl, CURLOPT_POSTFIELDS, $queryString );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec( $curl );
$error = curl_getinfo( $curl );
curl_close( $curl );
if ( $error['http_code'] != "200" )
{
$this->errno = '0';
$this->error = 'Ошибка соединения';
return false;
}
else
{
$answer = json_decode( $result );
if( !isset( $answer->response ) )
{
if( isset( $answer->error ) )
{
$this->errno = $answer->error->error_code;
$this->error = $answer->error->error_msg;
$this->requestFields = $answer->error->request_params;
}
else $this->error = 'Неопознанная ошибка.';
return false;
}
else return $answer->response;
}
}
/**
* Формирует строку запроса
*/
private function createQueryString()
{
$string = '';
foreach( $this->_parameters as $name=>$value ) $string .= $name . '=' . urlencode( $value ) . '&';
$string .= 'sig=' . $this->createSIG();
return $string;
}
/**
* Создаёт подпись запроса
*/
private function createSIG()
{
$string = '';
ksort( $this->_parameters, SORT_STRING );
foreach( $this->_parameters as $name=>$value ) $string .= $name . '=' . $value;
$string .= $this->_secureCode;
return md5( $string );
}
/**
* Возвращает случайную строку для обеспечения уникальности запроса
*/
private function getRandom()
{
return BaseString::randomStr();
}
/**
* Возвращает текущее значение unixtime на сервере
*/
private function getTimestamp()
{
return DateTimeUtils::date();
}
}
Примечание. Класс использует утилиты из GMFramework. Но все такие использования заключены в отдельные методы с описанием, так что при желании можно просто переписать их, без использования GMFramework.
Использование, на примере совершения транзакции (снятие голосов со счёта пользователя на счёт приложения):
function transferVotes( $votes, $userId = 0 )
{
$userId = (float)$userId;
if( $votes < 0 || $userId <= 0 ) return false;
if( $votes == 0 ) return true;
$votes = (int)( $votes * 100 );
$invoker = new SecureRequest( API_ID ); // API_ID - константа, содержащая идентификатор приложения
if( $result = $invoker->request( SecureRequest::WITHDRAW_VOTES, array( 'uid' => $userId, 'votes' => $votes ) ) )
{
if( (int)$result == $votes ) return true;
else {
// ошибка перевода голосов
return false;
}
}
else {
// здесь можно отдельно обраотать ошибки,
// например ошибка $invoker->errno == 502 - у пользователя на счету нет голосов
return false;
}
}