Использование VK Payments API в IFrame-приложениях

в 15:35, , рубрики: Песочница, метки: , , ,
Использование VK Payments API в IFrame-приложениях - 1

В данной статье будет рассмотрен пример создания простого IFrame-приложения с использованием VK Payments API.

Для нормальной работы потребуется сервер, а также домен с подключенным SSL-сертификатом.

Создание и настройка приложения

Для начала нужно перейти в раздел для разработчиков и нажать на кнопку «Создать приложение».

Использование VK Payments API в IFrame-приложениях - 2

Далее придумываем название для приложения и выбираем его тип «IFrame/Flash приложение».
Остальные поля заполняем на свое усмотрение.

Использование VK Payments API в IFrame-приложениях - 3

После нажатия кнопки «Перейти к загрузке приложения», нам предложат подтвердить свои действия. Подтверждаем.

Использование VK Payments API в IFrame-приложениях - 4

После подтверждения, попадаем на страницу «Редактирование приложения», на которой мы и будем настраивать наше приложение.

Использование VK Payments API в IFrame-приложениях - 5

В левом меню выбираем раздел «Настройки».
На этой странице достаточно будет выбрать «Тип приложения: IFrame» и ввести адрес сайта на котором будет размещено наше IFrame-приложение. Сохраняем изменения.

Использование VK Payments API в IFrame-приложениях - 6

В левом меню выбираем раздел «Платежи».
Вписываем «Адрес обратного вызова» и в «Тестеры платежей» выбираем себя. Сохраняем изменения.

Использование VK Payments API в IFrame-приложениях - 7

«Тестовый режим позволяет тестировать функциональность покупки товаров и перевода голосов в приложениях без реальной передачи голосов».

Для работы Payments API этих настроек будет достаточно. Теперь можно переходить к следующему шагу.

Файлы и База данных

Создаем такие файлы на сервере:

index.php

<?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>
styles.css

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;
}
output.php

<?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;
?>
db.php

<?php
    // Подключаемся к БД
    $pdo = new PDO('mysql:host=localhost;dbname=dbname;charset=utf8', 'dbuser', 'dbpass');
?>
buy.php

<?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;
?>
vk_callback.php

<?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-запрос на создание таблицы с нужными нам полями.

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 в IFrame-приложениях - 8

Ссылки

Документация по VK Payments API
Оригинальный код vk_callback.php

  1. admin:

    а можно попросить работающий исходник в архиве пожалуйста?

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js