Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Адрес API для интеграций

API — адрес, который вызывает не человек в браузере, а другая программа: складская система передаёт остатки, бухгалтерская забирает заказы. Полноценного REST API в OpenCart нет. Для обмена с внешней системой обычно пишут свой контроллер, который принимает JSON и проверяет ключ доступа.

Контроллер

Создайте контроллер витрины в дополнении:

// extension/acme_hello/catalog/controller/api/stock.php
namespace Opencart\Catalog\Controller\Extension\AcmeHello\Api;
 
class Stock extends \Opencart\System\Engine\Controller
{
    public function index(): void
    {
        $json = ['status' => 'ok'];
 
        $this->response->addHeader('Content-Type: application/json');
        $this->response->setOutput(json_encode($json));
    }
}

Проверьте его из консоли:

curl "http://shop.test/index.php?route=extension/acme_hello/api/stock"

Команда выведет ответ JSON с ключом status.

Ключ доступа

Адрес открыт всем, поэтому первым делом контроллер проверяет секретный ключ. Ключ хранится в настройках модуля — добавьте в форму настроек поле module_acme_hello_api_key — и приходит в заголовке запроса:

$key = (string) ($this->request->server['HTTP_X_API_KEY'] ?? '');
$expected = (string) $this->config->get('module_acme_hello_api_key');
 
if ($expected === '' || !hash_equals($expected, $key)) {
    $this->response->addHeader($this->request->server['SERVER_PROTOCOL'] . ' 401 Unauthorized');
    $this->response->addHeader('Content-Type: application/json');
    $this->response->setOutput(json_encode(['error' => 'Неверный ключ API']));
 
    return;
}

Запрос без правильного ключа получает статус 401. hash_equals() сравнивает строки так, что ключ нельзя подобрать по времени ответа.

Приём данных

Тело запроса — JSON, его читают из php://input:

$items = json_decode(file_get_contents('php://input'), true) ?: [];
 
foreach ($items as $item) {
    $this->db->query(
        "UPDATE `" . DB_PREFIX . "product` SET `quantity` = '" . (int) ($item['quantity'] ?? 0) . "'
         WHERE `sku` = '" . $this->db->escape((string) ($item['sku'] ?? '')) . "'"
    );
}
 
$json = ['updated' => count($items)];

В готовом дополнении запрос переносят в модель.

curl -X POST "http://shop.test/index.php?route=extension/acme_hello/api/stock" \
    -H "X-API-Key: your-secret-key" -H "Content-Type: application/json" \
    -d '[{"sku": "MUG-001", "quantity": 15}]'

Команда выведет ответ JSON, где updated равно 1, а у товара с артикулом MUG-001 в Catalog → Products количество станет 15.

Данные, прочитанные из php://input, не проходят через $this->request, поэтому движок их не экранирует. Числа приводите к типу, а строки экранируйте сами.

Встроенный API

У OpenCart есть собственный API с ключами, которые создают в System → Users → API: имя, ключ и список разрешённых IP-адресов. Им пользуется сама панель, когда сотрудник редактирует заказ: маршруты под api/ собирают корзину и пересчитывают итоги. Набор маршрутов и способ входа менялись между выпусками 4.0 и 4.1, поэтому опираться на него во внешней интеграции рискованно. Чтобы изучить его, посмотрите контроллеры в catalog/controller/api/ своей копии.

Частая ошибка

Ключ передают в адресе: ...&key=your-secret-key. Адреса попадают в журналы веб-сервера, историю браузера и журналы прокси, и ключ утекает. Передавайте ключ в заголовке и принимайте запросы только по HTTPS.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.