Pull to refresh

PHP-библиотека для работы с API Яндекс.Денег

Reading time6 min
Views11K
Yandex.Money APIМне давно хотелось попробовать что-нибудь новенькое, и вот, когда на работе предложили написать примеры использования API Яндекс.Денег на разных языках, я с удовольствием принял это предложение-challenge. Так как чаще всего подобный функционал используют в приложениях на различных хостингах, то было принято волевое решение первым делом попробовать написать сие на PHP. Причем API до этого я даже не видел; более того, никакого опыта работы с PHP, кроме как лабораторной в ВУЗе, у меня не было. Дело обещало быть интересным.

Выбор окружения


Первое, с чем я столкнулся: разрабатывать и деплоить тут же на хостинг не очень удобно. И я решил скачать какой-нибудь джентльменский набор для web-разработчика. Из студенческих времен в памяти маячило название Denwer. Попробовал, но быстро отказался от него. Он живет какой-то своей жизнью, и когда я пытался настроить его, переписав что-нибудь в conf-файле Apache, он затирал или не затирал это по своему усмотрению, не давая все настроить руками. То есть получилось, что не я его настраивал, а он меня. Напомнило «если б я имел коня — это был бы номер...». В итоге я его, конечно, победил, но решил при этом найти более простой WAMP-server. Хочу отметить, что Denwer хороший продукт и ничего против я не имею, но читать факи и мануалы по нему мне не захотелось.

Нашел страничку со списком WAMP'ов в вики и стал перебирать их. Основными критерием для выбора были поддерживаемость проекта, чтобы версия сборки была более-менее свежей, и простота установки/запуска. В итоге смело могу рекомендовать The Uniform Server. Он не требует установки (только распаковать архив), при запуске висит в трее и запускается легким нажатием =). Самовольничать он не стал, и я остановился на нем.

Аутентификация OAuth


Почитал инструкции, скачал документацию, оголил шашку и помчался в бой. Но в бою я был быстро повержен OAuth-аутентификацией. OAuth — это способ получить доступ к какому-либо сервису/аккаунту пользователя без ввода и хранения его логина и пароля в своем приложении. Пришло к нам это от создателя твиттера и выглядит примерно так: мы делаем запрос к сервису (в нашем случае – к Яндекс.Деньгам), пользователь вводит на сервере Яндекс.Денег свой логин/пароль и дает нашему приложению разрешения пользоваться его аккаунтом. После этого сервер Яндекс.Денег делает редирект на наше приложение, и мы получаем временный код, время жизни которого очень мало. Затем посредством еще одного запроса к Яндекс.Деньгам меняем этот временный код на постоянный токен пользователя и дальше для нас, как для дембеля, все дороги открыты.

Правда, пока я проходил OAuth-аутентификацию, наткнулся на проблему безопасности. Попробовал обращаться к серверу Яндекс.Денег, но PHP стал грязно ругаться и говорить что-то про сертификаты. Порыскал немного в интернете и понял, что нужно, чтобы наше приложение проверяло SSL-сертификат сервера. Хотелось сделать хорошо, чтобы гарантировать пользователям безопасность, и я продолжил поиски. Но вменяемых примеров реализации проверки сертификата сервера в рунете почти нет. Расскажу по порядку.

Сначала нужно было прописать проверку сертификатов в коде при отправке запросов. Как заставить cURL, которым я пользуюсь, отправлять запросы с проверкой сертификата? Начал искать и был поражен тем, что самый популярный совет при ошибках сертификатов: ОТКЛЮЧИТЬ проверку. И это предлагают на куче сайтов и форумов (к примеру, тут). Ужас, в общем. Вот код, который чаще всего предлагают:

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

Запомните его, дети, и никогда не пишите. «А теперь, сынок, повторим все те плохие слова, которые ты должен забыть». Слава богу, что в англоязычном интернете не все так плохо и я нашел такую ссылочку, которая все объяснила. Сделал, как там написано, и все заработало.

Затем нужно было сохранить публичный сертификат Яндекс.Денег у себя, чтобы было с чем сравнивать при отправке запросов. Я вроде не совсем отсталый, но тем не менее мне это показалось довольно непростым. Может, вам в будущем поможет при работе с SSL. Заходим на нужный сайт через https, тыкаем в сертификаты и экспортируем. Но их там 3, какой из них нужен? «Возьми с полки пирожок; их там два, возьми средний». Оказывается, нужно экспортировать сертификат центра сертификации (корневой) и промежуточный (Яндекса). Конечный сертификат меняется раз в год и, если впишем его в цепочку и забудем поменять, когда он протухнет, то все в нашем приложении поломается. Поэтому экспортируем только указанные 2 сертификата и просто сохраняем их в один текстовый файл (скриншот). В моей библиотеке он фигурирет как ym.crt.

После этого запросы у меня заработали. Ура! Дальнейшее было делом техники. В документации все было понятно; собственно, поэтому я ее фактически и закопипастил в документацию кода. Оговорюсь еще, что писал я ее как объектную; на мой взгляд, с объектами работать хорошо и удобно.

Шифрование


Еще были небольшие трудности с шифрованием. Сначала сохранение/восстановление токенов пользователей было реализовано стандартной PHP-библиотекой Mcrypt. Но, как выяснилось, с ней есть проблемы. Например, из экзамплов, взятых в мануале, сразу заработала только одна deprecated-функция. Остальные функции плевали на мое желание заставить их работать, и лишь говорили что-то о неудачной инициализации модуля. Надо было разбираться. Затем выяснилось, что хостеры не очень жалуют эту библиотеку. Спросил у поддержки своего хостера, почему при создании сайта на PHP 5.3 нет модуля Mcrypt. Мне ответили (дословно): «Он годами глючил в 5.2 — автоматом не внесли в 5.3 как модуль, о котором вспоминают раз в пять лет, а проблемы с ним были». Других удобных стандартных библиотек с реализацией симметричного шифрования я в PHP не нашел (есть библиотека OpenSSL, но она не совсем для этого). После этого библиотеку шифрования я решил сменить на phpseclib, которая является открытой и поддерживает популярный алгоритм AES. Она заработала сразу и без проблем.

Функционал и примеры использования


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

В результате реализованы вызовы следующих функций API Яндекс.Денег: информация о счете, история операций, детальная информация по операциям, переводы денег другим пользователям. Плюсы и возможности:
  • OAuth-авторизация пользователя;
  • безопасность работы (поддерживается проверка цепочки сертификатов);
  • удобство работы (response'ы сервера представлены в виде объектов) и быстрый старт;
  • относительно безопасное и простое решение хранения токенов пользователей с использованием шифрования и без использования БД. Реализацию этого решения вы сможете легко переписать под свои хранилища.

Сама библиотека представляет собой файл цепочки сертификатов ym.crt и файл ym.php, который содержит:
  • программный интерфейс IYandexMoney;
  • главный класс YandexMoney (реализация интерфейса);
  • класс-перечисление с правами доступа (scope);
  • вспомогательные классы (response-объекты вывода результатов запросов к API).
В комплект библиотеки приложены 2 файла, которые реализуют шифрование: Rijndael.php и AES.php. Данные файлы взяты из библиотеки phpseclib. Они нужны на случай, если вы будете использовать методы сохранения и восстановления токенов.
Внимание: использует PHP версии 5, а также стандартную библиотеку cUrl для http-запросов.

Для тех, кто не будет устанавливать и смотреть подробные примеры, покажем пару вызовов.
Для выполнения операций со счетом через API необходимо получить разрешение пользователя, то есть токен. Его можно получить следующими вызовами (к примеру, с доступом на просмотр информации о счете и истории операций):

YandexMoney::authorize(Consts::CLIENT_ID, 'account-info operation-history', Consts::REDIRECT_URL);

// затем на странице редиректа инициировать создание объекта и получение токена
$ym = new YandexMoney(Consts::CLIENT_ID, Consts::CERTIFICATE_CHAIN_PATH);	
$token = $ym->receiveOAuthToken($_GET['code'], Consts::REDIRECT_URL);

При создании объекта $ym ему передается идентификатор приложения и абсолютный путь на сервере к цепочке сертификатов (файл ym.crt). И то, и другое обычно прописывается в константах в каком-нибудь модуле (consts.php в наших примерах).
Ну и покажем, как получить информацию о счете пользователя. Таким же образом создаем объект и затем вызываем метод, передав ему токен пользователя:

$ym = new YandexMoney(Consts::CLIENT_ID, Consts::CERTIFICATE_CHAIN_PATH);
$accountInfoResponse = $ym->accountInfo($token);			

echo 'Номер счета: ' . $accountInfoResponse->getAccount() . "\n";
echo 'Баланс: ' . $accountInfoResponse->getBalance() . "\n";
echo 'Код валюты: ' . $accountInfoResponse->getCurrency() . "\n";

Информация о счете получена.

Примерно так же обстоят дела и с другими вызовами.

В итоге, библиотеку решили назвать громким именем SDK и выложить на GitHub.
Буду рад услышать ваши замечания и предложения, а также увидеть форки и пулл-реквесты.
Tags:
Hubs:
Total votes 61: ↑50 and ↓11+39
Comments14

Articles