Программирование, веб-кодинг

Автоматический прием Яндекс.Денег на сайте на php

Как на Yii2 реализовать HTTP-уведомление для yandex оплаты?

Автоматический прием Яндекс.Денег на сайте на php

Для начала генерируем адрес и секретный ключ для уведомления здесь - https://money.yandex.ru/myservices/online.xml

В моём случае указываю адрес url:

http://site.ru/receive

Таким образом после оплаты, Яндекс обратится к контроллеру receive и отправит туда данные об оплате. Я же в этом контроллере обработаю эти данные как желаю: могу письмо на почту админу отправить, могу сразу в БД добавить запись о платеже, или открыть нужный уровень доступа в личном кабинете оплатившего.

Теперь создам в контроллере действие receive:

public function beforeAction($action) {
        if ($action->id === 'receive') {
                    $this->enableCsrfValidation = false; //отключаем CSRF, так извне вызываем наш скрипт джастом
                }
                return parent::beforeAction($action);
    }
    
    public function actionReceive()
    {
        $secret_key = 'xxxxxxxxxxxx..xx'; // секретное слово, которое мы получили в предыдущем шаге.
 
        // возможно некоторые из нижеперечисленных параметров вам пригодятся
        // $_POST['operation_id'] - номер операция
        // $_POST['amount'] - количество денег, которые поступят на счет получателя
        // $_POST['withdraw_amount'] - количество денег, которые будут списаны со счета покупателя
        // $_POST['datetime'] - тут понятно, дата и время оплаты
        // $_POST['sender'] - если оплата производится через Яндекс Деньги, то этот параметр содержит номер кошелька покупателя
        // $_POST['label'] - лейбл, который мы указывали в форме оплаты
        // $_POST['email'] - email покупателя (доступен только при использовании https://)
         
        $sha1 = sha1( $_POST['notification_type'] . '&'. $_POST['operation_id']. '&' . $_POST['amount'] . '&643&' . $_POST['datetime'] . '&'. $_POST['sender'] . '&' . $_POST['codepro'] . '&' . $secret_key. '&' . $_POST['label'] );
         
        if ($sha1 != $_POST['sha1_hash'] ) {
            // тут содержится код на случай, если верификация не пройдена
            Yii::$app->mailer->compose()
            ->setTo('info@site.ru')
            ->setFrom(['info@site.ru' => 'Оплата курса'])
            ->setSubject('Курс не оплачен')
            ->setTextBody("E-mail: ".$_POST['operation_id']."\n Телефон: ".$_POST['label'])
            ->send();
            exit();
        }
         
        // тут код на случай, если проверка прошла успешно
        Yii::$app->mailer->compose()
            ->setTo('info@site.ru')
            ->setFrom(['info@site.ru' => 'Оплата курса'])
            ->setSubject('Курс успешно оплачен')
            ->setTextBody("дата и время оплаты: ".Yii::$app->request->post('datetime', null).
                        "/n/rномер операции: ".Yii::$app->request->post('operation_id', null).
                        "/n/rколичество денег, которые поступят на счет получателя: ".Yii::$app->request->post('amount', null).
                        "/n/rколичество денег, которые будут списаны со счета покупателя: ".Yii::$app->request->post('withdraw_amount', null).
                        "/n/rномер кошелька покупателя: ".Yii::$app->request->post('sender', null).
                        "/n/rлейбл, который мы указывали в форме оплаты: ".Yii::$app->request->post('label', null).
                        "/n/remail покупателя: ".Yii::$app->request->post('email', null))
            ->send();
        exit();
    }

Здесь отключил CSRF для этого экшна, чтобы POST-запрос принялся от Яндекса.

Секретный ключ вводим из Яндекса, тот, что сгенерировали на первом шаге.

Далее производится проверка sha1. Читаем в документации Яндекса:

Всегда проверяйте значение параметра sha1_hash. Это нужно, чтобы удостовериться:

  • в целостности данных уведомления;
  • в том, что уведомление отправлено Яндекс.Деньгами.


Что делать, если HTTP-уведомление от Яндекс не работает:

Возможно, вы указали https, а сайт у вас открывается только по http.

Или csrf не отключили для этого действия receive.

Ищите ошибку и исправляйте её.