В данной статье будет рассмотрен пример создания простого IFrame-приложения с использованием VK Payments API.
Для нормальной работы потребуется сервер, а также домен с подключенным SSL-сертификатом.
Создание и настройка приложения
Для начала нужно перейти в раздел для разработчиков и нажать на кнопку «Создать приложение».
Далее придумываем название для приложения и выбираем его тип «IFrame/Flash приложение».
Остальные поля заполняем на свое усмотрение.
После нажатия кнопки «Перейти к загрузке приложения», нам предложат подтвердить свои действия. Подтверждаем.
После подтверждения, попадаем на страницу «Редактирование приложения», на которой мы и будем настраивать наше приложение.
В левом меню выбираем раздел «Настройки».
На этой странице достаточно будет выбрать «Тип приложения: IFrame» и ввести адрес сайта на котором будет размещено наше IFrame-приложение. Сохраняем изменения.
В левом меню выбираем раздел «Платежи».
Вписываем «Адрес обратного вызова» и в «Тестеры платежей» выбираем себя. Сохраняем изменения.
«Тестовый режим позволяет тестировать функциональность покупки товаров и перевода голосов в приложениях без реальной передачи голосов».
Для работы Payments API этих настроек будет достаточно. Теперь можно переходить к следующему шагу.
Файлы и База данных
Создаем такие файлы на сервере:
<?php
$viewer_id = $_GET['viewer_id']; // Получаем ID пользователя
// Добавляем нового пользователя в БД
include 'db.php';
$stmt = $pdo->prepare('INSERT INTO payments (users) VALUES ("'.$viewer_id.'")');
$stmt->execute();
$pdo = null;
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Payments API</title>
<script type="text/javascript" src="//vk.com/js/api/xd_connection.js"></script>
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
function order(coin) {
var params = {
type: 'item',
item: 'item_'+coin+'coin'
};
VK.callMethod('showOrderBox', params);
var callbacksResults = document.getElementById('callbacks');
VK.addCallback('onOrderSuccess', function(order_id) {
callbacksResults.innerHTML = 'Платеж <b>'+order_id+'</b> успешно завершен!';
var coin_1 = parseInt($('#coins').text());
var coin_2 = parseInt(coin);
var coin_3 = coin_1 + coin_2;
$('#coins').text(coin_3);
});
VK.addCallback('onOrderFail', function() {
callbacksResults.innerHTML = 'Платеж не был обработан!';
});
VK.addCallback('onOrderCancel', function() {
callbacksResults.innerHTML = 'Платеж отменен!';
});
}
function buy(coin) {
if($('#coins').text() == 0) {
$('#callbacks').text('Вы растратили все монеты!');
} else {
$.ajax({
type: "POST",
url: "buy.php",
data: {
"buy-1":"<?php echo $viewer_id; ?>",
"buy-2":coin
}
});
var coin_1 = parseInt($('#coins').text());
var coin_2 = parseInt(coin);
var coin_3 = coin_1 - coin_2;
$('#coins').text(coin_3);
$('#callbacks').text('Потрачено '+coin+' монет!');
}
}
</script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="main">
<div class="header">
<a href="index.php" class="left-link">Payments API</a>
<a href="#" onclick="VK.External.showInviteBox();" class="right-link">Пригласить друзей</a>
<div class="coins">Монеты: <span id="coins"><?php include 'output.php'; ?></span></div>
</div>
<div class="content">
<div id="callbacks">...</div>
<div class="left-block">
<div class="title">Получить монеты</div>
<a href="#" onclick="order(100)">Получить 100 монет</a>
<a href="#" onclick="order(200)">Получить 200 монет</a>
<a href="#" onclick="order(300)">Получить 300 монет</a>
<a href="#" onclick="order(400)">Получить 400 монет</a>
<a href="#" onclick="order(500)">Получить 500 монет</a>
<a href="#" onclick="order(600)">Получить 600 монет</a>
<a href="#" onclick="order(700)">Получить 700 монет</a>
<a href="#" onclick="order(800)">Получить 800 монет</a>
<a href="#" onclick="order(900)">Получить 900 монет</a>
<a href="#" onclick="order(1000)">Получить 1000 монет</a>
</div>
<div class="right-block">
<div class="title">Потратить монеты</div>
<a href="#" onclick="buy(100)">Потратить 100 монет</a>
<a href="#" onclick="buy(200)">Потратить 200 монет</a>
<a href="#" onclick="buy(300)">Потратить 300 монет</a>
<a href="#" onclick="buy(400)">Потратить 400 монет</a>
<a href="#" onclick="buy(500)">Потратить 500 монет</a>
<a href="#" onclick="buy(600)">Потратить 600 монет</a>
<a href="#" onclick="buy(700)">Потратить 700 монет</a>
<a href="#" onclick="buy(800)">Потратить 800 монет</a>
<a href="#" onclick="buy(900)">Потратить 900 монет</a>
<a href="#" onclick="buy(1000)">Потратить 1000 монет</a>
</div>
</div>
</div>
</body>
</html>
html, body {
background: #EEF2F6;
font: 14px Arial;
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
#main {
position: relative;
width: 607px;
height: 500px;
}
.header {
background: #FFFFFF;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
height: 50px;
line-height: 50px;
padding: 0px 10px;
}
.left-link {
display: block;
width: 180px;
height: 50px;
line-height: 50px;
color: #404C58;
text-align: center;
float: left;
}
.left-link:hover {
background: #F7F9FA;
}
.right-link {
display: block;
width: 180px;
height: 50px;
line-height: 50px;
color: #404C58;
text-align: center;
float: right;
}
.right-link:hover {
background: #F7F9FA;
}
.coins {
text-align: center;
}
#callbacks {
background: #FFFFFF;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
text-align: center;
margin: 10px 10px 0px 10px;
padding: 10px;
border-radius: 3px;
}
.left-block {
background: #FFFFFF;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
width: 250px;
margin: 10px;
padding: 15px;
float: left;
border-radius: 3px;
}
.right-block {
background: #FFFFFF;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1);
width: 250px;
margin: 10px;
padding: 15px;
float: right;
border-radius: 3px;
}
.title {
font-size: 16px;
padding-bottom: 10px;
}
.left-block a, .right-block a {
color: #404C58;
display: block;
}
.left-block a:hover, .right-block a:hover {
color: #3DAC4A;
}
<?php
include 'db.php';
$stmt = $pdo->prepare('SELECT * FROM payments WHERE users="'.$viewer_id.'"');
$stmt->execute();
$data = $stmt->fetchAll();
$result = $data[0]['coins'];
print_r($result);
$pdo = null;
?>
<?php
// Подключаемся к БД
$pdo = new PDO('mysql:host=localhost;dbname=dbname;charset=utf8', 'dbuser', 'dbpass');
?>
<?php
$viewer_id = $_POST['buy-1'];
$coins = $_POST['buy-2'];
include 'db.php';
$stmt = $pdo->prepare('INSERT INTO payments (users, coins) VALUES ("'.$viewer_id.'", "'.$coins.'") ON DUPLICATE KEY UPDATE coins=(coins-"'.$coins.'")');
$stmt->execute();
$pdo = null;
?>
<?php
header("Content-Type: application/json; encoding=utf-8");
$secret_key = 'QaWULKcGEKwGt1iBRseS'; // Защищенный ключ приложения
$input = $_POST;
// Проверка подписи
$sig = $input['sig'];
unset($input['sig']);
ksort($input);
$str = '';
foreach ($input as $k => $v) {
$str .= $k.'='.$v;
}
if ($sig != md5($str.$secret_key)) {
$response['error'] = array(
'error_code' => 10,
'error_msg' => 'Несовпадение вычисленной и переданной подписи запроса.',
'critical' => true
);
} else {
// Подпись правильная
switch ($input['notification_type']) {
case 'get_item':
// Получение информации о товаре
$item = $input['item']; // наименование товара
if ($item == 'item_100coin') {
$response['response'] = array(
'item_id' => 100,
'title' => '100 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 1
);
} elseif ($item == 'item_200coin') {
$response['response'] = array(
'item_id' => 200,
'title' => '200 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 2
);
} elseif ($item == 'item_300coin') {
$response['response'] = array(
'item_id' => 300,
'title' => '300 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 3
);
} elseif ($item == 'item_400coin') {
$response['response'] = array(
'item_id' => 400,
'title' => '400 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 4
);
} elseif ($item == 'item_500coin') {
$response['response'] = array(
'item_id' => 500,
'title' => '500 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 5
);
} elseif ($item == 'item_600coin') {
$response['response'] = array(
'item_id' => 600,
'title' => '600 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 6
);
} elseif ($item == 'item_700coin') {
$response['response'] = array(
'item_id' => 700,
'title' => '700 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 7
);
} elseif ($item == 'item_800coin') {
$response['response'] = array(
'item_id' => 800,
'title' => '800 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 8
);
} elseif ($item == 'item_900coin') {
$response['response'] = array(
'item_id' => 900,
'title' => '900 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 9
);
} elseif ($item == 'item_1000coin') {
$response['response'] = array(
'item_id' => 1000,
'title' => '1000 золотых монет',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 10
);
} else {
$response['error'] = array(
'error_code' => 20,
'error_msg' => 'Товара не существует.',
'critical' => true
);
}
break;
case 'get_item_test':
// Получение информации о товаре в тестовом режиме
$item = $input['item'];
if ($item == 'item_100coin') {
$response['response'] = array(
'item_id' => 100,
'title' => '100 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 1
);
} elseif ($item == 'item_200coin') {
$response['response'] = array(
'item_id' => 200,
'title' => '200 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 2
);
} elseif ($item == 'item_300coin') {
$response['response'] = array(
'item_id' => 300,
'title' => '300 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 3
);
} elseif ($item == 'item_400coin') {
$response['response'] = array(
'item_id' => 400,
'title' => '400 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 4
);
} elseif ($item == 'item_500coin') {
$response['response'] = array(
'item_id' => 500,
'title' => '500 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 5
);
} elseif ($item == 'item_600coin') {
$response['response'] = array(
'item_id' => 600,
'title' => '600 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 6
);
} elseif ($item == 'item_700coin') {
$response['response'] = array(
'item_id' => 700,
'title' => '700 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 7
);
} elseif ($item == 'item_800coin') {
$response['response'] = array(
'item_id' => 800,
'title' => '800 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 8
);
} elseif ($item == 'item_900coin') {
$response['response'] = array(
'item_id' => 900,
'title' => '900 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 9
);
} elseif ($item == 'item_1000coin') {
$response['response'] = array(
'item_id' => 1000,
'title' => '1000 золотых монет (тестовый режим)',
'photo_url' => 'https://mysite.com/coin.png',
'price' => 10
);
} else {
$response['error'] = array(
'error_code' => 20,
'error_msg' => 'Товара не существует.',
'critical' => true
);
}
break;
case 'order_status_change':
// Изменение статуса заказа
if ($input['status'] == 'chargeable') {
$order_id = intval($input['order_id']);
$user_id = intval($input['user_id']);
$item_id = intval($input['item_id']);
include 'db.php';
$stmt = $pdo->prepare('INSERT INTO payments (users, coins, orders) VALUES ("'.$user_id.'", "'.$item_id.'", "'.$order_id.'") ON DUPLICATE KEY UPDATE coins=(coins+"'.$item_id.'"), orders="'.$order_id.'"');
$stmt->execute();
$pdo = null;
// Код проверки товара, включая его стоимость
$app_order_id = 1; // Получающийся у вас идентификатор заказа.
$response['response'] = array(
'order_id' => $order_id,
'app_order_id' => $app_order_id,
);
} else {
$response['error'] = array(
'error_code' => 100,
'error_msg' => 'Передано непонятно что вместо chargeable.',
'critical' => true
);
}
break;
case 'order_status_change_test':
// Изменение статуса заказа в тестовом режиме
if ($input['status'] == 'chargeable') {
$order_id = intval($input['order_id']);
$user_id = intval($input['user_id']);
$item_id = intval($input['item_id']);
include 'db.php';
$stmt = $pdo->prepare('INSERT INTO payments (users, coins, orders) VALUES ("'.$user_id.'", "'.$item_id.'", "'.$order_id.'") ON DUPLICATE KEY UPDATE coins=(coins+"'.$item_id.'"), orders="'.$order_id.'"');
$stmt->execute();
$pdo = null;
$app_order_id = 1; // Тут фактического заказа может не быть - тестовый режим.
$response['response'] = array(
'order_id' => $order_id,
'app_order_id' => $app_order_id,
);
} else {
$response['error'] = array(
'error_code' => 100,
'error_msg' => 'Передано непонятно что вместо chargeable.',
'critical' => true
);
}
break;
}
}
echo json_encode($response);
?>
Создаем базу данных и выполняем в ней SQL-запрос на создание таблицы с нужными нам полями.
CREATE TABLE IF NOT EXISTS `payments` (
`users` int(15) DEFAULT NULL,
`coins` int(15) NOT NULL DEFAULT '0',
`orders` int(15) DEFAULT NULL,
UNIQUE KEY `users` (`users`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
В результате мы получим вот такое приложение:
Ссылки
Документация по VK Payments API
Оригинальный код vk_callback.php
а можно попросить работающий исходник в архиве пожалуйста?