среда, 16 июля 2014 г.

Qiwi. Форма и обработка запроса

Статья о платежной системе Qiwi. Рассмотрим только html форму и обработку запроса от сервера. Это можно использовать, например, для пополнения счета или оплату товара на сайте.

PULL (REST) протокол


Вместо старой html формы рассмотрим новый протокол, который полностью ее заменил
Сначала нужно выставить пользователю счет. Для этого отправим запрос через cURL:
$url = 'https://w.qiwi.com/api/v2/prv/'.$shopid.'/bills/'.$id;
$loginPass = $apiid.':'.$pass;
$lifetime = date('c', time() + 86400);
$parameters = array(
    "user" => "tel:+".intval($mobile),
    "amount" => $amount,
    "ccy" => $currency,
    "comment" => $comment,
    "lifetime" => $lifetime,
    "pay_source" => "qw"
);
$headers = array(
 "Accept: application/json",
 "Content-Type: application/x-www-form-urlencoded; charset=utf-8"
);
$parameters = http_build_query($parameters);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $loginPass);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
curl_setopt($ch, CURLOPT_POST, 1);
$httpResponse = curl_exec($ch);
$results = json_decode($httpResponse);
$result_code = $results->response->result_code;
$description = $results->response->description;

$shopid - Идентификатор вашего магазина
$id - ID платежа в вашей системе. Будет использован для поиска нужного платежа в вашей БД
$apiid - Ваш API ID
$pass - Пароль API
$mobile - Телефон (аккаунт) пользователя, на который будет выставлен счет
$amount - Сумма, на которую выставляется счет
$currency - Валюта. По-умолчанию доступна только RUB (рубли РФ)
$comment - Описание платежа
$lifetime - Время, которое выставленный счет будет активен (можно оплатить). В примере - сутки.
$result_code - Код ответа сервера. Если не равен 0 - ошибка.
$description - Текст ошибки, если она есть

Счет выставили, теперь нужно отправить пользователя на оплату. Сгенерируем ссылку:
$url = 'https://w.qiwi.com/order/external/main.action?shop='.$shopid.'&transaction='.$id.'&successUrl='.$success_url.'&failUrl='.$fail_url.'&qiwi_phone='.$mobile;

$shopid - Идентификатор вашего магазина (тот-же, что и выше)
$id - ID платежа в вашей системе. Будет использован для поиска нужного платежа в вашей БД (тот-же, что и выше)
$success_url - Ссылка на страницу успешной оплаты (Вернуться на ваш сайт после оплаты)
$fail_url - Ссылка на страницу ошибки или отказа от оплаты (Вернуться на ваш сайт после неудачной оплаты)
$mobile - Телефон (аккаунт) пользователя, на который будет выставлен счет (тот-же, что и выше)

И отправляем пользователя на этот URL, например так:
header('Location: '.$url);


Настройка аккаунта


Настроить аккаунт можно по адресу: https://ishop.qiwi.com/balance/overview.action (официальный сайт Qiwi)
Нужно создать проект: "Новый проект". Поля элементарные, описывать не буду. Обратите внимание, что API будут работать только после проверки проекта администрацией Qiwi (статус "Подтвержден").
Переходим в настройки проекта, кликом на его название:
Аутентификационные данные для всех протоколов - Сгенерировать новый ID. Записать в свою БД (Идентификатор - переменная $apiid в этой статье, пароль - переменная $pass)
Идентификатор магазина - Записать в свою БД (переменная $shopid в этой статье)
Настройки Pull (REST) протокола - Включить
Включить уведомления - Включить
URL для оповещения - Ссылка на файл обработки операции. Описание содержания этого файла смотрите в пункте "Обработка запроса" этой статьи
Сменить пароль оповещения - нажать и сохранить пароль в БД (переменная $key в этой статье)
Подпись - Отметить галочкой


Обработка запроса


После оплаты платежная система присылает запрос на указанный вами URL для оповещения. В этом файле, в первую очередь, необходимо проверить подлинность запроса, ведь он мог быть запущен не платежной системой. После чего уже делаем нужны операции: изменение статуса платежа в вашей БД или пополнение счета пользователя на сайте. Начнем по порядку.
Система присылает следующие данные (сразу сократим названия переменных, зачем нам в коде длинные переменные?):
$id          =trim($_POST['bill_id']);
$status      =trim($_POST['status']);
$error       =trim($_POST['error']);
$amount      =trim($_POST['amount']);
$user        =trim($_POST['user']);
$prv_name    =trim($_POST['prv_name']);
$ccy         =trim($_POST['ccy']);
$comment     =trim($_POST['comment']);
$command     =trim($_POST['command']);
$head        =apache_request_headers();
$hash        =$head['X-Api-Signature'];

bill_id - ID платежа в вашей системе
status - Статус платежа. Успешный: paid
error - Ошибка, если она есть
amount - Сумма платежа
user - Телефон (аккаунт) пользователя, который оплатил счет
ccy - Валюта платежа
comment - Описание платежа
X-Api-Signature - Подпись запроса (хеш)

Теперь нужно проверить хеш. Это обязательное действие. Без него безопасность данной операции будет близка к нулю.
Создадим свой вариант хеша, по возможности используя данные из своей БД (постфикс _bd в переменных; используйте $id для поиска нужной транзакции):
$hash_gen = base64_encode(hash_hmac("sha1", $amount_bd.'|'.$id.'|'.$ccy_bd.'|'.$command.'|'.$comment.'|'.$error.'|'.$prv_name.'|'.$status.'|'.$user_bd, $key, $raw_output=TRUE));
if($hash_gen!=$hash) // ошибка

Переменная $key - пароль оповещения, который вы встречали в настройках аккаунта

С проверками закончили. Теперь можно сделать то, ради чего этот запрос пришел - изменить статус транзакции или пополнить счет пользователя, на ваше усмотрение. И эти действия я описывать не буду - все в ваших руках.

Осталось только вернуть системе правильный ответ.
Ответ для успешного завершения:
header("HTTP/1.1 200 OK");
header('content-type: text/xml; charset=UTF-8');
echo '0'; 
exit; 

Для завершения с ошибкой - измените result_code (0) на другой:
5 - Ошибка формата параметров запроса
13 - Ошибка соединения с базой данных
150 - Ошибка проверки пароля
151 - Ошибка проверки подписи
300 - Ошибка связи с сервером

Вот и все, запрос завершен и эта статья тоже.


4 комментария:

  1. У меня проблема, как только я не делал, не приходят уведомления или обработчик не верный. Сделал как у Вас, все равно от qiwi тишина. Они как пример отправляют запрос:

    POST /qiwi-notify.php HTTP/1.1
    Accept: application/xml
    Content-type: application/x-www-form-urlencoded
    Authorization: Basic MjA0Mjp0ZXN0Cg==
    bill_id=BILL-1&status=paid&error=0&amount=1.00&user=tel%3A%2B79031811737&
    prv_name=Retail_Store&ccy=RUB&comment=test&command=bil

    как его правильно обработать? Я голову сломал... Ваш вариант не работает

    ОтветитьУдалить
    Ответы
    1. Для начала стоит убедиться, что запросы от Qiwi вообще приходят. Поставить вверху обработчика запись произвольного текста в какой-нибудь файл, например. Если запрос не доходит - проверять пути и доступ к файлу со сторонних серверов (создать curl запрос к нему с другого хостинга, как вариант). Если запрос пройдет, то уже надо постепенно вычислять проблему в обработчике. Записывать в файл все переменные, что присылает Qiwi и т.д.
      Сообщите, что получится проверить. Возможно, подскажу в чем проблема.

      Удалить
  2. приветствую.
    вы, видимо, опечатались.
    в строке генерации хеша уберите '_bd' из имён переменных $amount_bd, $ccy_bd и $user_bd

    ОтветитьУдалить
  3. Хорошая статья, единственное функция апача не работало , сделал так -
    $hash =$_SERVER['HTTP_X_API_SIGNATURE'];

    ОтветитьУдалить