Адрес 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.