haikiri/mikbill

MikBiLL PHP SDK for working with clients.

1.4.0 2025-05-24 16:56 UTC

This package is auto-updated.

Last update: 2025-05-24 17:29:47 UTC


README

MikBiLL PHP SDK для работы с клиентами. Получение токена, данных клиентов. Управление подписками, отписками и т.д...

⚙️ Рекомендации, зависимости, стандарты

  • Рекомендуемая версия PHP: >=8.0

  • Необходимые расширения:

    • curl
  • Код полностью соответствует стандартам:

📦 Установка

composer require haikiri/mikbill

📚 Ссылки

💬 Напоследок:

Обрати внимание, что почти над каждым методом в исходном коде были оставлены комментарии. Но некоторые поля описаны неполно, либо вообще не описаны, потому что официальной документации на каждое поле БД – нет. Будет круто, если ты поможешь заполнить пробелы и знаешь что за что отвечает...

Если в каком-то объекте нет нужной модели, нет времени ждать внесения изменений, ты можешь использовать метод: getAsArray – он вернёт тебе традиционный response["data"] массив данных, напрямую из запроса. getData - он позволит обращаться к вложенным массивам в стиле "точки.доступа", например getData("info.name").

Если хочешь дополнить библиотеку — напиши по контактам в composer.json.

📂 Структура

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

Эта SDK библиотека будет наполняться по мере необходимости, возможностей и откликов. Теперь большинство методов и примеры их использования будут перечислены либо в wiki, либо в папке тестирования tests/. Не стесняйтесь сообщать про работоспособность методов, которые не были перечислены здесь. Контакты в composer.json.

Пример официальной API структуры и готовности этого SDK:

  • На что вы можете рассчитывать:

    • [F] - Функционал завершён.
    • [MD] - Основной функционал завершён. (Дочерние методы, возможно, могут быть добавлены позднее)
    • [P] - В приоритете. (По планам завершить в ближайшее время)
    • [MP] - Средний приоритет. (Было бы хорошо иметь, но не критично, когда-нибудь...)
    • [LP] - Низкий приоритет. (Возможно появление базового функционала для некоторых методов в будущем)
  • Billing API [F]

    • Users [F]
  • Cabinet API

    • Auth [F]
    • Tickets [F]
    • Common [F]
    • Packet [MD]
    • User (>=50%) [MD]
      • Contacts (0%) [MP]
    • Register Hotpost [LP]
      • type 1
      • type 2
    • Payments [LP]
    • Services [MP]
      • Turbo [F]
      • Freeze [F]
      • Real IP [MP]
      • Credit [F]
      • Change MAC [LP]
      • Money Transfers [LP]
    • Subscriptions [MD]
      • Additional [F]
      • Middleware [F]
      • Other [F]
      • Прочие Middleware [LP]
    • Devices 🆕 [LP]
    • Reports [LP]
    • News [F]

Ошибки и исключения

Проект поддерживает легкую обработку ошибок с помощью исключений. Если вам необходимо более детальная возможность отлова ошибок, вы можете заменить входную точку этого SDK на свой класс. Вы не в клетке. Пример с чего начать собственную реализацию входной точки SDK смотри по ссылке: Своя реализация sendRequest. Строка 100.

  • Исключения, которые могут быть выброшены в стандартной реализации SDK:
    • BillApiException — отлавливает ответы биллинга и возвращает оригинальный код и текст ошибки.
    • UnauthorizedException — вызывается если произошла ошибка получения данных в следствии ошибки авторизации.
    • Throwable — используйте их для отлова всех остальных ошибок.

Important

Полный список исключений можете найти в src/Exception

🧯 Обработка ошибок

Оборачивай вызовы в try-catch чтобы отловить исключения:

try {
    /**
    * Здесь выполняйте запросы к API, чтобы отлавливать ошибки.
    */

} catch (\Haikiri\MikBiLL\Exception\UnauthorizedException $e) {
    // Сами придумаете как обрабатывать такие ошибки...
	echo "<hr><h2>Не удалось авторизовать запрос: <code>[{$e->getCode()}]</code></h2>";
	echo $e->getMessage();
} catch (\Haikiri\MikBiLL\Exception\BillApiException $e) {
	echo "<hr><h2>MikBiLL прислал в ответ ошибку: <code>[{$e->getCode()}]</code></h2>";
	echo $e->getMessage();
} catch (\Exception $e) {
	echo "<hr><h2>Неизвестная ошибка: <code>[{$e->getCode()}]</code></h2>";
	echo $e->getMessage();
}

🚀 Пример использования

1. Инициализация проекта

Используй эту базовую конструкцию где-нибудь в своём проекте, чтобы инициализировать SDK:

require "vendor/autoload.php";

use Haikiri\MikBiLL\MikBiLLApi;

$MikBiLL = new MikBiLLApi(
    url: "https://api.example.com/", # Твой Api сервер.
    key: "yourApiSignKey", # Твой Api ключ для подписи запросов.
);

2. Логирование

Есть возможность записывать все json ответы в стандартный вывод error_log:

$MikBiLL::$debug = true;

3. Проксирование

Если по какой-либо причине есть необходимость в прокси-сервере:

$MikBiLL->isProxy = false; # true чтобы включить
$MikBiLL->proxy_addr = "10.11.12.13";
$MikBiLL->proxy_port = 8080;
$MikBiLL->proxy_user = "userName";
$MikBiLL->proxy_pass = "userPassword";

Note

По умолчанию используется socks5. Ты можешь добавить следующий параметр для использования других версий, например 4:

$MikBiLL->proxy_type = CURLPROXY_SOCKS4;

4. Получение токена

Токен можно получить двумя вариантами:

  • По UID клиента — через подписанный запрос в Billing API.
  • По логину и паролю — через Cabinet API.

Important

Обрати внимание, что: Для работы с клиентом через cabinet сначала необходимо получить и записать токен клиента через setUserToken. Для работы с админ запросами через billing нужен ключ для подписи billing запросов (см. ШАГ 1 - использования SDK).

Пример получения токена клиента по его UID:

$billing_uid = 13; # UID клиента в MikBiLL.
$token = $MikBiLL->billing->Users()->getUserToken(uid: $billing_uid);

Пример получения токена по логину и паролю:

$token = $MikBiLL->cabinet->Auth()
	->login("userLogin", "userPassword")
	->getToken();

echo $token
	? "Успешно авторизовались."
	: "Не удалось авторизоваться.";

5. Хранение и использование токена

Токен необходимо сразу-же сохранить во внутреннем хранилище которое реализуется интерфейсом:

$MikBiLL->setUserToken(token: $token);

Ты можешь запросить токен в любой момент используя следующий геттер:

$MikBiLL->getUserToken();

Пример как увидеть токен на странице php:

echo "<h3>token:</h3>";
echo "<code style='font-size: 18px;'>{$MikBiLL->getUserToken()}</code><hr>";

6. Получение данных клиента

Ты можешь получить данные клиента используя ранее полученный токен:

$user = $MikBiLL->cabinet->User()->getUser();
echo "<h2>[{$user->getUserFirstName()} {$user->getUserMiddleName()}]</h2>"; # Пример использования модели.
echo "<h3>Массив данных клиента:</h3>";
echo "<pre>" . print_r($user->getData(), true) . "</pre><hr>"; # Пример просмотра массива, если не устраивают модели.

7. Поиск клиента

Ты можешь искать клиентов по определённому критерию и обработать их:

Обрати внимание, что биллинг через поиск возвращает только основные данные, нежели по токену через API кабинета. Это значит, что большая часть возвращаемой модели окажется пустой.

# Пример поиска всех клиентов у которых 'state' равен (=) '4' (то есть удалён):
$searchResult = $MikBiLL->billing->Users()->searchUser(
    key: "state",     # Указываем ключ 'state'
    value: "4",       # state - это статус клиента: (1 - обычный, 2 - заморожен, 3 - отключен, 4 - удален)
    operator: "=",    # Возможные операторы: ['<', '=', '>', '>=', '!='] или ['меньше', 'равно', 'больше', 'больше или равно', 'не равно']
);

echo "<h3>Список удалённых клиентов:</h3>";
foreach ($searchResult->getUsers() as $user) {
    echo "<h2>[uid: {$user->getUserId()}] – {$user->getUserFirstName()} {$user->getUserMiddleName()}</h2>";
}

Простой вариант, если тебе нужны данные только конкретного клиента по его UID:

echo "<h3>Данные конкретного клиента:</h3>";
$billing_uid = 13; # UID клиента в MikBiLL.
$user = $MikBiLL->billing->Users()->searchUser(value: $billing_uid)->getOne();
echo "<h2>[uid: {$user->getUserId()}] – {$user->getUserFirstName()} {$user->getUserMiddleName()}</h2>";

8. Подписки

Ты можешь увидеть список всех доступных подписок клиенту на данный момент.

После обновления API, появилась возможность прописывать в аргументе сервис, чтобы работать с определённым middleware.

echo "<h3>Доступные подписки клиенту:</h3>";
$middleware = "other"; # Название сервиса. Используйте "other" чтобы получить все доступные пользовательские подписки.

$subs = $MikBiLL->cabinet->Subscriptions()->getSubscriptions(service: $middleware);
foreach ($subs->getSubscription() as $sub) {
    echo "<hr><h2><code>[id:{$sub->getId()}] " . $sub->getName() . "</code></h2>";
    echo "<li>Цена: {$sub->getServicePrice()} {$sub->getCurrency()}.</li>";
    echo "<p>Описание: {$sub->getDescription()}</p>";
}

Можно подписать клиента на услугу по её идентификатору и названию сервиса.

  • 1 - активировать услугу
  • 0 - отключить услугу. (можно оставить пустым для отключения)

🆕 В аргументе service: необходимо указывать название услуги. Актуальный список middleware можно узнать в официальном MikBiLL API: Ссылка на документацию

К сожалению, нет возможности проверить middleware подписки. Однако, "other" возвращает все доступные подписки клиента.

ВАЖНО! Используй следующий метод, чтобы управлять подписками, которые не принадлежат middleware. Метод для установки подписок: $MikBiLL->cabinet->Subscriptions()->setAdditional(id: $id, activate: 1/0);

Объяви переменные:

$id = 123; # ID услуги.
$middleware = "wink"; # Название сервиса.

Вот пример как подписать клиента на услугу:

$status = $MikBiLL->cabinet->Subscriptions()->setSubscription(id: $id, activate: 1, service: $middleware);

echo $status
	? "Успешно оформили подписку №$id сервиса $middleware."
	: "Не удалось оформить подписку №$id сервиса $middleware.";

Пример как отписать клиента от услуги:

$status = $MikBiLL->cabinet->Subscriptions()->setSubscription(id: $id, service: $middleware);

echo $status
	? "Успешно отписались от подписки №$id сервиса $middleware."
	: "Не удалось отписаться от подписки №$id сервиса $middleware.";

Появилась возможность получить список доступных Middleware подписок для клиента. Для удобства были сделаны модели и массивы. Можешь использовать вариант "как-есть" для ручной обработки данных.

Пример получения списка доступных Middleware:

echo "<h3>Доступные Middleware как модель:</h3>";
$wares = $MikBiLL->cabinet->Subscriptions()->getMiddlewares();
foreach ($wares->getMiddlewares() as $ware) {
	echo "<hr><h2><code>[id:{$ware->getId()}] " . $ware->getName() . "</code></h2>";
}

Пример использования после преобразования в массив:

echo "<h3>Доступные Middleware как массив:</h3>";
$wares = $MikBiLL->cabinet->Subscriptions()->getMiddlewares();
foreach ($wares->getAsArray() as $ware) {
	echo "<hr><h2><code>[id:{$ware["id"]}}] " . $ware["name"] . "</code></h2>";
}

У данного метода есть вариант вернуть данные "как-есть" для более ручной обработки:

echo "<h3>Массив Middleware как-есть:</h3>";
$wares = $MikBiLL->cabinet->Subscriptions()->getMiddlewares()->getAsIs();
echo "<pre>" . print_r($wares, true) . "</pre>";

Ты можешь получить список дополнительных подписок (не привязанных к middleware).

Используй метод getAsIs() чтобы получить массив данных как-есть и работать с ним самостоятельно.

$getAdditional = $MikBiLL->cabinet->Subscriptions()->getAdditional();
echo "<pre>" . print_r($getAdditional->getAsIs(), true) . "</pre>";

Метод управления подписками не привязанным к middleware схожий с setSubscription:

$id = 102; # ID подписки.
$sub = $MikBiLL->cabinet->Subscriptions()->setAdditional(id: $id, activate: 1); # Подписаться
$unSub = $MikBiLL->cabinet->Subscriptions()->setAdditional(id: $id, activate: 0); # Отписаться
# В ответ всё так-же приходит boolean.

9. Тикеты: Создание, отправка, чтение

Клиент может увидеть все свои тикеты:

echo "<h3>Тикеты клиента:</h3>";
$tickets = $MikBiLL->cabinet->Tickets()->getTickets();
foreach ($tickets->getMessages() as $ticket) {
	$status = $ticket->isClosed() ? "📛 [закрыто]" : "⏳ [открыто]";
	echo "<hr><h2><small>$status</small> Обращение: <code>[id:{$ticket->getId()}]</code> | открыто " . ($ticket->getDate()?->format("d.m.Y в H:i:s") ?? "") . "</h2>";
	echo "<p>Первое сообщение:</p><code>{$ticket->getMessage()}</code>";
}
//echo "<pre>" . print_r($tickets->getAsArray(), true) . "</pre>";

Клиент может создать новый тикет:

$text = "Это сообщение с которым будет создан тикет.";
$ticket = $MikBiLL->cabinet->Tickets()->newTicket($text);

echo $ticket->getId()
	? "<hr><h2><code>Зарегистрировано новое обращение [id:{$ticket->getId()}]</code></h2>"
	: "<hr><h2><code>Не удалось зарегистрировать обращение.</code></h2>";

//echo "<pre>" . print_r($ticket->getData(), true) . "</pre>";

Клиент может отправлять сообщения в тикет:

$id = 3; # ID тикета.
$text = "Это сообщение будет дополнено в тикет.";
$sentStatus = $MikBiLL->cabinet->Tickets()->sendMessage(ticketId: $id, message: $text);
echo $sentStatus
	? "<hr><h2><code>Сообщение отправлено.</code></h2>"
	: "<hr><h2><code>Не удалось отправить сообщение.</code></h2>";

Клиент может видеть переписку в выбранном тикете:

$id = 3; # ID тикета.
$tickets = $MikBiLL->cabinet->Tickets()->getTicketsDialog(ticketId: $id);
foreach ($tickets->getMessages() as $ticket) {
	$type = $ticket->isMessageFromClient() ? "клиент" : "оператор";

	$name = $ticket->isMessageFromClient()
		? trim("{$ticket->getUserFirstName()} {$ticket->getUserMiddleName()}") # Обращаемся к клиенту по Имени и Отчеству.
		: $ticket->getOperatorLogin();

	echo "<hr><p>[Сообщение №{$ticket->getMessageId()}] написал $type <b>$name</b></p>";
	echo "<p>Сообщение:</p><code>{$ticket->getMessageTest()}</code>";
}

Для большей гибкости, ты можешь посмотреть массив сообщений выбранного тикета:

$id = 3; # ID тикета.
echo "<h3>Массив сообщений тикета #$id:</h3>";
$ticket = $MikBiLL->cabinet->Tickets()->getTicketsDialog(ticketId: $id);
echo "<pre>" . print_r($ticket->getAsArray(), true) . "</pre>";

10. Common

Ты можешь получить IP адрес клиента:

$getIp = $MikBiLL->cabinet->Common()->getIp();
echo "<h3>Получаем: IP клиента</h3>";
echo "<ul>";
echo "<li>IP из модели: <code>{$getIp->getIp()}</code></li>";
echo "<li>IP из массива: <code>" . $getIp->getData()["ip"] . "</code></li>";
echo "</ul>";
//echo "<pre>" . print_r($getIp->getData(), true) . "</pre>";

Ты можешь получить время сервера:

$getDate = $MikBiLL->cabinet->Common()->getDate();
echo "<h3>Получаем: Дата и Время</h3>";
echo "<ul>";
echo "<li>Управляемая дата и время: <code>" . $getDate->getDateTime()->format("d.m.Y H:i:s") . "</code></li>";
echo "<li>Дата из массива: <code>" . $getDate->getData()["format"] . "</code></li>";
echo "<li>Time Stamp: <code>" . $getDate->getTimeStamp() . "</code></li>";
echo "</ul>";
//echo "<pre>" . print_r($getDate->getData(), true) . "</pre>";

Ты можешь узнать версию MikBiLL:

$getVersion = $MikBiLL->cabinet->Common()->getVersion();
echo "<h3>Получаем: Версия MikBiLL</h3>";
echo "<ul>";
echo "<li>Версия: <code>$getVersion</code></li>";
echo "</ul>";

Ты можешь получить меню личного кабинета:

$getMenu = $MikBiLL->cabinet->Common()->getMenu();
echo "<h3>Получаем: Меню</h3>";
echo "<ul>";
foreach ($getMenu->getMenus() as $menu) {
	echo "<li><a id='{$menu->getId()}' href='{$menu->getUri()}' class='{$menu->getIcon()}'>{$menu->getName()}</a></li>";
}
echo "</ul>";
//echo "<pre>" . print_r($getMenu->getAsArray(), true) . "</pre>";

Ты можешь получить данные организации:

$getContact = $MikBiLL->cabinet->Common()->getContact();
echo "<h3>Получаем: Контактные данные организации</h3>";
echo "<ul>";
echo "<li>Компания: <code>{$getContact->getName()}</code></li>";
echo "<li>Адрес: <code>{$getContact->getAddress()}</code></li>";
echo "<li>Сайт: <code>{$getContact->getSite()}</code></li>";
echo $getContact->getEmail() ? "<li>Email: <code>{$getContact->getEmail()}</code></li>" : "";
echo $getContact->getPhoneName1() ? "<li>{$getContact->getPhoneName1()}: <code>{$getContact->getPhoneNumber1()}</code></li>" : "";
echo $getContact->getPhoneName2() ? "<li>{$getContact->getPhoneName2()}: <code>{$getContact->getPhoneNumber2()}</code></li>" : "";
echo $getContact->getPhoneName3() ? "<li>{$getContact->getPhoneName3()}: <code>{$getContact->getPhoneNumber3()}</code></li>" : "";
echo "<li>Показать карту: <code>" . ($getContact->isShowMap() ? "Да" : "Нет") . "</code></li>";
echo "</ul>";
//echo "<pre>" . print_r($getContact->getData(), true) . "</pre>";

Ты можешь получить некую конфигурацию:

Метод не реализован полностью, и возможно, вряд ли появится желание заполнять эту модель. Используйте getAsArray() для ручной работы с массивами.

$getConfig = $MikBiLL->cabinet->Common()->getConfig();
echo "<h3>Получаем: Конфигурацию (массив)</h3>";
echo "<pre>" . print_r($getConfig->getAsArray(), true) . "</pre>";

11. Новости

Клиент может увидеть (персональные) новости:

$getNews = $MikBiLL->cabinet->News()->getNews();
echo "<h3>Получаем: Новости</h3>";
foreach ($getNews->getNews() as $news) {
	echo "<hr><ul>";
	echo "<li>ID: <code>{$news->getId()}</code></li>";
	echo "<li>Тема: <code>{$news->getSubject()}</code></li>";
	echo "<li>Новость:<br><textarea maxlength=\"50\">{$news->getText()}</textarea></li>";
	echo "</ul>";
}

12. Тарифы

Клиент может получить список доступных тарифов:

$getPackets = $MikBiLL->cabinet->Packet()->getPackets();
echo "<h3>Получаем: Список тарифов</h3>";
foreach ($getPackets->getPackets() as $packet) {
	echo "<hr><ul>";
	echo "<li>Тариф <code>{$packet->getName()} [{$packet->getId()}]</code></li>";
	echo "<li>Цена: <code>{$packet->getPrice()} {$packet->getCurrency()}.</code></li>";
	echo "<li>Цена со скидкой: <code>{$packet->getPriceDiscounted()} {$packet->getCurrency()}.</code></li>";
	echo "</ul>";
}

Можно посмотреть детали тарифа по его ID:

Метод не реализован полностью, и возможно, вряд ли появится желание заполнять эту модель. Используйте getData() для ручной работы с массивами.

$id = 31; #	ID Тарифа.
$packet = $MikBiLL->cabinet->Packet()->getPacketInfo(packetId: $id);
echo "<h3>Получаем: Детали тарифа #$id</h3>";
echo "<ul>";
echo "<li>Тариф: <code>{$packet->getName()} [id:{$packet->getId()}]</code></li>";
echo "<li>Цена: <code>{$packet->getData()["fixed_cost"]} {$packet->getData()["currency"]}.</code></li>";
echo "<li>Суточная цена: <code>{$packet->getDailyCost()} {$packet->getCurrency()}.</code></li>";
echo "<li>Скорость: <code>{$packet->getSpeedRate()}</code></li>";
echo "</ul>";
echo "<pre>" . print_r($packet->getData(), true) . "</pre>";