Каждый, кто хоть раз пытался прикрутить оплату к своему сайту, знает: это как первый поход в тренажерный зал. Вроде просто, но вокруг столько железа, что страшно. А если серьезно — интеграция платежных систем в PHP — это не ракетостроение, но требует внимания к деталям. В этой статье разберем, как это сделать правильно, без боли и лишних нервов.
С чего начать: выбираем платежную систему
Прежде чем писать код, нужно понять, через кого принимать деньги. Вариантов много: от гигантов вроде ЮKassa и PayPal до узкоспециализированных сервисов. Критерии выбора простые:
- Комиссия — сколько процентов заберет сервис с каждой транзакции.
- Способы оплаты — карты, СБП, электронные кошельки, криптовалюта.
- Сложность интеграции — есть ли готовые SDK для PHP, документация на русском.
- Техподдержка — насколько быстро отвечают, если что-то сломалось.
- Требования к сайту — нужен ли HTTPS, есть ли ограничения по CMS.
Вот небольшая таблица для сравнения популярных вариантов:
| Система | Комиссия | Способы оплаты | PHP SDK | Особенности |
|---|---|---|---|---|
| ЮKassa | от 3.5% | Карты, СБП, кошельки | Да | Хорошая документация, много настроек |
| PayPal | от 3.4% + фикс | Карты, PayPal balance | Да | Международная, но сложно с выводом в РФ |
| Robokassa | от 3.9% | Карты, СБП, терминалы | Да | Популярна в СНГ, много валют |
| Stripe | от 2.9% + фикс | Карты, Apple Pay, Google Pay | Да | Мощный API, но нет официальной поддержки в РФ |
Если ваш проект ориентирован на российский рынок, берите ЮKassa или Robokassa. Если планируете международные продажи — Stripe или PayPal, но учтите ограничения.
Основные сценарии интеграции
Как вообще работает прием платежей? Есть два основных подхода: редирект и прямое списание.
Редирект — самый простой и безопасный. Клиент нажимает «Оплатить», его перенаправляет на сайт платежной системы, там он вводит данные карты, а потом возвращается обратно на ваш сайт. Вам не нужно иметь дело с карточными данными, а это снижает требования к безопасности.
Прямое списание — когда клиент вводит данные карты прямо на вашем сайте, а вы отправляете их в платежную систему через API. Это удобнее для пользователя, но требует соблюдения стандартов безопасности PCI DSS. Обычно используется, если у вас есть сертификат и ресурсы.
Для большинства небольших проектов достаточно редиректа. Он проще в реализации и не требует сложного кода.
Вот как выглядит типичный сценарий с редиректом:
- Клиент оформляет заказ и выбирает оплату.
- PHP-скрипт создает платеж через API платежной системы.
- Получает от системы ссылку для редиректа.
- Перенаправляет клиента на эту ссылку.
- Клиент платит.
- Платежная система отправляет вам уведомление (webhook) о результате.
- Вы обновляете статус заказа.
Звучит просто, но есть нюансы. Давайте разберем их на примере с ЮKassa.
Практический пример: интеграция с ЮKassa
Чтобы не быть голословным, покажу, как подключить ЮKassa. Возьмем простой сценарий: создание платежа и обработка уведомления.
Сначала установим SDK через Composer. Если не знаете, что это — это менеджер пакетов для PHP, упрощает жизнь.
composer require yoomoney/yookassa-sdk-php
Теперь напишем скрипт для создания платежа. Допустим, у нас есть сумма и описание заказа.
<?php
require_once 'vendor/autoload.php';
use YooKassa\Client;
$client = new Client();
$client->setAuth('shopId', 'secretKey'); // Ваши данные из личного кабинета
$payment = $client->createPayment(
array(
'amount' => array(
'value' => '100.00', // Сумма в рублях
'currency' => 'RUB',
),
'confirmation' => array(
'type' => 'redirect',
'return_url' => 'https://mysite.ru/payment-success.php', // Куда вернуть клиента
),
'capture' => true, // Сразу списываем деньги
'description' => 'Заказ #123',
'metadata' => array(
'order_id' => '123', // Свой идентификатор заказа, пригодится потом
),
),
uniqid('', true) // Уникальный ключ идемпотентности
);
// Получаем ссылку для редиректа
$confirmationUrl = $payment->getConfirmation()->getConfirmationUrl();
// Отправляем клиента на оплату
header('Location: ' . $confirmationUrl);
exit;
?>
Что здесь происходит? Мы создаем объект клиента, авторизуемся, передаем сумму, способ подтверждения (редирект), описание и метаданные. В ответ получаем объект платежа, из которого берем ссылку для перенаправления. Все просто.
Но это только половина дела. Нужно еще обработать уведомление от платежной системы, чтобы обновить статус заказа.
Обработка уведомлений (webhook)
Платежная система после оплаты отправит на ваш сервер POST-запрос с данными о платеже. Этот запрос называется webhook. Ваша задача — его принять, проверить подпись и обновить статус заказа.
Важно: webhook может прийти в любой момент, поэтому обработчик должен быть защищен от подделок. ЮKassa подписывает запрос с помощью HMAC-SHA256. Проверим подпись.
<?php
require_once 'vendor/autoload.php';
use YooKassa\Model\Notification\NotificationSucceeded;
use YooKassa\Model\Notification\NotificationWaitingForCapture;
use YooKassa\Model\Notification\NotificationCanceled;
// Получаем тело запроса
$source = file_get_contents('php://input');
$headers = getallheaders();
// Проверяем подпись (заголовок Content-Signature)
$signature = $headers['Content-Signature'] ?? '';
$shopId = 'shopId';
$secretKey = 'secretKey';
$expectedSignature = base64_encode(hash_hmac('sha256', $source, $secretKey, true));
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(400);
exit('Invalid signature');
}
// Декодируем JSON
$data = json_decode($source, true);
// Создаем объект уведомления в зависимости от типа события
$notification = null;
switch ($data['event']) {
case 'payment.succeeded':
$notification = new NotificationSucceeded($data);
break;
case 'payment.waiting_for_capture':
$notification = new NotificationWaitingForCapture($data);
break;
case 'payment.canceled':
$notification = new NotificationCanceled($data);
break;
default:
http_response_code(400);
exit('Unknown event');
}
$payment = $notification->getObject();
$orderId = $payment->getMetadata()['order_id'];
$status = $payment->getStatus();
// Обновляем статус заказа в своей базе данных
// Например: UPDATE orders SET status = 'paid' WHERE id = $orderId;
// Отвечаем платежной системе, что все ок
http_response_code(200);
exit('OK');
?>
Обратите внимание: мы проверяем подпись, иначе злоумышленник может отправить поддельное уведомление и пометить заказ оплаченным, не заплатив. Это критически важно.
Также стоит помнить, что уведомления могут приходить повторно, поэтому обработчик должен быть идемпотентным — то есть повторная обработка не должна вызвать ошибок.
Обработка возвратов и отмен
Клиенты бывают разные: кто-то передумал, кто-то случайно оплатил не тот товар. Поэтому рано или поздно понадобится функция возврата средств.
В ЮKassa возврат делается просто — через API. Пример:
<?php
require_once 'vendor/autoload.php';
use YooKassa\Client;
$client = new Client();
$client->setAuth('shopId', 'secretKey');
$refund = $client->createRefund(
array(
'payment_id' => 'payment-id-здесь', // ID платежа, который нужно вернуть
'amount' => array(
'value' => '100.00',
'currency' => 'RUB',
),
),
uniqid('', true)
);
echo 'Возврат создан: ' . $refund->getId();
?>
Здесь все аналогично созданию платежа: авторизуемся, передаем ID платежа и сумму возврата. Важно: сумма возврата не может превышать сумму платежа, и вернуть можно только ту часть, которая еще не была возвращена.
Также учтите, что деньги возвращаются не мгновенно — обычно это занимает от нескольких секунд до нескольких дней в зависимости от банка.
Типичные ошибки и как их избежать
Даже опытные разработчики иногда наступают на грабли. Вот список самых частых проблем:
- Неправильная проверка подписи. Если не проверить подпись, ваша система уязвима для атак. Всегда используйте hash_equals для сравнения, чтобы избежать timing-атак.
- Игнорирование повторных уведомлений. Платежная система может отправить уведомление несколько раз. Сделайте обработку идемпотентной: если заказ уже оплачен, не изменяйте его статус повторно.
- Хранение секретного ключа в коде. Никогда не вставляйте ключи прямо в скрипт. Используйте переменные окружения или конфигурационные файлы, которые не попадают в git.
- Отсутствие обработки ошибок. API может вернуть ошибку — например, при неверной сумме или недостатке средств. Обрабатывайте исключения и логируйте их.
- Неверный формат суммы. Некоторые платежные системы ожидают сумму в копейках, другие — в рублях с десятичной точкой. Внимательно читайте документацию.
Заключение
Интеграция платежных систем в PHP — задача решаемая. Главное — выбрать подходящую систему, внимательно изучить документацию и не забывать о безопасности. Начните с простого редиректа, добавьте обработку webhook и возвраты — и ваш сайт готов принимать деньги.
В итоге, вот что важно запомнить:
- Выбирайте платежную систему под свои задачи и регион.
- Используйте редирект, если не хотите возиться с PCI DSS.
- Обязательно проверяйте подпись в webhook.
- Тестируйте на тестовых данных перед запуском.
- Храните ключи в безопасности.
Если остались вопросы — не стесняйтесь, читайте документацию вашей платежной системы. Там, как правило, все подробно расписано. Удачи в приеме платежей!



